TPM and PKCS-11 backed crypto/rand Reader
A crypto.rand reader that uses a Trusted Platform Module (TPM) as the source of randomness.
Basically, its just a source of randomness used to create RSA keys or just get bits for use anywhere else. With tpm2-tools
, its like this:
$ tpm2_getrandom --hex 32
8c20c96c56d3ac200881ac86505020a0dafcfe0224fbc51b843e07625cc779fc
As background, the default rand generator with golang uses the following sources by default in rand.go
The implementation uses go-tpm's tpm2.GetRandom function as the source of randomness from the hardware.
From there, the usage is simple:
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"flag"
"fmt"
//"time"
"github.com/google/go-tpm/legacy/tpm2"
//"github.com/cenkalti/backoff/v4"
tpmrand "github.com/salrashid123/tpmrand"
)
var (
tpmPath = flag.String("tpm-path", "/dev/tpm0", "Path to the TPM device (character device or a Unix socket).")
)
func main() {
rwc, err := tpm2.OpenTPM(*tpmPath)
if err != nil {
fmt.Printf("Unable to open TPM at %s", *tpmPath)
}
defer rwc.Close()
randomBytes := make([]byte, 32)
r, err := tpmrand.NewTPMRand(&tpmrand.Reader{
TpmDevice: rwc,
//Scheme: backoff.NewConstantBackOff(time.Millisecond * 10),
})
if err != nil {
fmt.Printf("%v\n", err)
return
}
// Rand read
_, err = r.Read(randomBytes)
if err != nil {
fmt.Printf("%v\n", err)
return
}
fmt.Printf("Random String :%s\n", base64.StdEncoding.EncodeToString(randomBytes))
fmt.Println()
// /// RSA keygen
privkey, err := rsa.GenerateKey(r, 2048)
if err != nil {
fmt.Printf("%v\n", err)
return
}
keyPEM := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privkey),
},
)
fmt.Printf("RSA Key: \n%s\n", keyPEM)
}
While you're here, some other references on TPMs and usage:
PKCS-11
ThalesIgnite crypto11.NewRandomReader() is an alternative to this library but requires installing tpm2-pkcs11 first on the library.
I've left some examples of using that library here for reference