-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do you have a function to return an rsa.PrivateKey from a CERT_CONTEXT? #37
Comments
I think I have adapted the code I found correctly. func unmarshalRSA(buf []byte) (*rsa.PrivateKey, error) {
// BCRYPT_RSA_BLOB -- https://learn.microsoft.com/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob
header := struct {
Magic uint32
BitLength uint32
PublicExpSize uint32
ModulusSize uint32
Prime1Size uint32
Prime2Size uint32
}{}
r := bytes.NewReader(buf)
if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
return nil, err
}
if header.Magic != 0x33415352 { // "RSA3" BCRYPT_RSAFULLPRIVATE_MAGIC
return nil, fmt.Errorf("invalid header magic %x", header.Magic)
}
if header.PublicExpSize > 8 {
return nil, fmt.Errorf("unsupported public exponent size (%d bits)", header.PublicExpSize*8)
}
// the exponent is in BigEndian format, so read the data into the right place in the buffer
exp := make([]byte, 8)
n, err := r.Read(exp[8-header.PublicExpSize:])
if err != nil {
return nil, fmt.Errorf("failed to read public exponent %w", err)
}
if n != int(header.PublicExpSize) {
return nil, fmt.Errorf("failed to read correct public exponent size, read %d expected %d", n, int(header.PublicExpSize))
}
mod := make([]byte, header.ModulusSize)
n, err = r.Read(mod)
if err != nil {
return nil, fmt.Errorf("failed to read modulus %w", err)
}
if n != int(header.ModulusSize) {
return nil, fmt.Errorf("failed to read correct modulus size, read %d expected %d", n, int(header.ModulusSize))
}
pk := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: new(big.Int).SetBytes(mod),
E: int(binary.BigEndian.Uint64(exp)),
},
D: new(big.Int),
Primes: make([]*big.Int, 2),
}
prime := make([]byte, header.Prime1Size)
n, err = r.Read(prime)
if err != nil {
return nil, fmt.Errorf("failed to read prime1 %w", err)
}
pk.Primes[0] = new(big.Int).SetBytes(prime)
prime = make([]byte, header.Prime2Size)
n, err = r.Read(prime)
if err != nil {
return nil, fmt.Errorf("failed to read prime2 %w", err)
}
pk.Primes[1] = new(big.Int).SetBytes(prime)
expBytes := make([]byte, 2*header.Prime1Size+header.Prime2Size+header.ModulusSize)
n, err = r.Read(expBytes)
if err != nil {
return nil, fmt.Errorf("Unable to read PrivateExponent %w", err)
}
pk.D = new(big.Int).SetBytes(expBytes[2*header.Prime1Size+header.Prime2Size:])
return pk, nil
} |
We are doing something similar in go-crypto-winnative/cng/rsa.go Lines 61 to 81 in 6eb9885
You code looks good, although using Also, you are not setting the precomputed values, which are present in the blob between the second prime number and the private exponent ( |
thx I put a todo in my code to revisit it. Long term - will there be a centralized push within the Microsoft org to consume a package like yours instead of writing home-grown Windows cert store interop code? The Go |
I'm not aware of any effort heading on that direction, and I doubt |
@qmuntal I've found some Go code to unmarshal an RSA public key, but I need similar code to unmarshal the output of
NCryptExportKey
to anrsa.PrivateKey
instance. I am a novice in this area so some guidance would be appreciated!The text was updated successfully, but these errors were encountered: