Created
August 19, 2024 01:42
-
-
Save ddz/ded489b1a5b05afb5f883c18ae005340 to your computer and use it in GitHub Desktop.
Load a key into Linux kernel keyring and use it via Crypto API userland interface (Linux >= 6.1)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/hex" | |
"fmt" | |
"log" | |
"io" | |
"os" | |
"golang.org/x/sys/unix" | |
) | |
func main() { | |
keySerial, err := addKey() | |
if err != nil { | |
log.Fatal(err) | |
} | |
hashfd, err := makeCipher(algTypeHash, algNameHmacSha1, keySerial) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// Assume hashfd is already configured using the setup process. | |
hash := os.NewFile(hashfd, "sha1") | |
// Hash an input string and read the results. Each Write discards | |
// previous hash state. Read always reads the current state. | |
b := make([]byte, 20) | |
for i := 0; i < 2; i++ { | |
io.WriteString(hash, "Hello, world.") | |
hash.Read(b) | |
fmt.Println(hex.EncodeToString(b)) | |
} | |
fmt.Println("Hello, World!") | |
} | |
// Linux keyring support | |
func addKey() (int, error) { | |
ringId, err := | |
unix.KeyctlGetKeyringID(unix.KEY_SPEC_PROCESS_KEYRING, true) | |
if err != nil { | |
return 0, err | |
} | |
// "logon" keys cannot be read from userspace, but can be used | |
keyId, err := unix.AddKey("logon", "testing:", []byte("thisisthekey"), | |
ringId) | |
if err != nil { | |
return 0, fmt.Errorf("AddKey: %w", err) | |
} | |
return keyId, nil | |
} | |
// | |
// Linux Crypto API userland interface: | |
// | |
// References: | |
// https://pkg.go.dev/golang.org/x/sys/unix#SockaddrALG | |
// http://www.chronox.de/crypto-API/crypto/userspace-if.html | |
// | |
type algType string | |
const ( | |
algTypeHash algType = "hash" | |
) | |
type algName string | |
const ( | |
algNameSha1 algName = "sha1" | |
algNameHmacSha1 = "hmac(sha1)" | |
) | |
func makeCipher(t algType, n algName, keySerial int) (uintptr, error) { | |
algFd, err := unix.Socket(unix.AF_ALG, unix.SOCK_SEQPACKET, 0) | |
if err != nil { | |
return 0, err | |
} | |
addr := &unix.SockaddrALG{Type: string(t), Name: string(n)} | |
err = unix.Bind(algFd, addr) | |
if err != nil { | |
return 0, err | |
} | |
// | |
// NB: Contrary to kernel docs, key must be set on bound socket, | |
// not socket returned by accept | |
// | |
err = unix.SetsockoptInt(int(algFd), unix.SOL_ALG, | |
unix.ALG_SET_KEY_BY_KEY_SERIAL, keySerial) | |
if err != nil { | |
return 0, fmt.Errorf("setsockopt %d", err) | |
} | |
// | |
// NB: unix.Accept does not work at this time; must invoke accept() | |
// manually using unix.Syscall. | |
// | |
fd, _, errno := unix.Syscall(unix.SYS_ACCEPT, uintptr(algFd), 0, 0) | |
if errno != 0 { | |
return 0, err | |
} | |
return fd, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment