Skip to content

Commit

Permalink
implement GenerateDSAKey
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Oct 21, 2023
1 parent 147ed74 commit c4ea81d
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 70 deletions.
151 changes: 83 additions & 68 deletions cng/das.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,133 +28,148 @@ func loadDSA() (h dsaAlgorithm, err error) {
return v.(dsaAlgorithm), nil
}

// DSAParameters contains the DSA parameters.
type DSAParameters struct {
P, Q, G, S BigInt
P, Q, G BigInt
}

func GenerateDSAParameters(l int) (DSAParameters, error) {
// GenerateDSAParameters generates a set of DSA parameters for a key of size L bytes.
// If L is less than or equal to 1024, the parameters are generated according to FIPS 186-2.
// If L is greater than 1024, the parameters are generated according to FIPS 186-3.
// The returned parameters are suitable for use in GenerateKey.
func GenerateDSAParameters(L int) (DSAParameters, error) {
h, err := loadDSA()
if err != nil {
return DSAParameters{}, err
}
// To generate the parameters, we need to generate a key pair and then export the public key.
// The public key contains the parameters. We then discard the key pair.
var hkey bcrypt.KEY_HANDLE
if err := bcrypt.GenerateKeyPair(h.handle, &hkey, uint32(l), 0); err != nil {
if err := bcrypt.GenerateKeyPair(h.handle, &hkey, uint32(L), 0); err != nil {
return DSAParameters{}, err
}
defer bcrypt.DestroyKey(hkey)

if err := bcrypt.FinalizeKeyPair(hkey, 0); err != nil {
return DSAParameters{}, err
}
if l <= 1024 {
hdr, data, err := exporDSAKey(hkey, false)
return getDSAParameters(hkey, L)
}

// DSAPrivateKey represents a DSA private key.
type DSAPrivateKey struct {
hkey bcrypt.KEY_HANDLE
}

func (k *DSAPrivateKey) finalize() {
bcrypt.DestroyKey(k.hkey)
}

// GenerateDSAKey generates a new private DSA key using the given parameters.
func GenerateDSAKey(params DSAParameters) (*DSAPrivateKey, error) {
h, err := loadDSA()
if err != nil {
return nil, err
}
var hkey bcrypt.KEY_HANDLE
if err := bcrypt.GenerateKeyPair(h.handle, &hkey, uint32(len(params.P))*8, 0); err != nil {
return nil, err
}
if err := setDSAParameter(hkey, params); err != nil {
bcrypt.DestroyKey(hkey)
return nil, err
}
if err := bcrypt.FinalizeKeyPair(hkey, 0); err != nil {
bcrypt.DestroyKey(hkey)
return nil, err
}
k := &DSAPrivateKey{hkey}
runtime.SetFinalizer(k, (*DSAPrivateKey).finalize)
return k, nil
}

// getDSAParameters returns the DSA parameters for the given key.
func getDSAParameters(hkey bcrypt.KEY_HANDLE, L int) (DSAParameters, error) {
var data []byte
consumeBigInt := func(size uint32) BigInt {
b := data[:size]
data = data[size:]
return b
}
var err error
if L <= 1024 {
var hdr bcrypt.DSA_KEY_BLOB
hdr, data, err = exporDSAKey(hkey, false)
if err != nil {
return DSAParameters{}, err
}
if hdr.Magic != bcrypt.DSA_PUBLIC_MAGIC || hdr.KeySize*8 != uint32(l) {
if hdr.Magic != bcrypt.DSA_PUBLIC_MAGIC || hdr.KeySize*8 != uint32(L) {
return DSAParameters{}, errors.New("crypto/dsa: exported key is corrupted")
}
consumeBigInt := func(size uint32) BigInt {
b := data[:size]
data = data[size:]
return b
}
return DSAParameters{
S: hdr.Seed[:],
Q: hdr.Q[:],
P: consumeBigInt(hdr.KeySize),
G: consumeBigInt(hdr.KeySize),
}, nil
}
hdr, data, err := exporDSAV2Key(hkey, false)
var hdr bcrypt.DSA_KEY_BLOB_V2
hdr, data, err = exporDSAV2Key(hkey, false)
if err != nil {
return DSAParameters{}, err
}
if hdr.Magic != bcrypt.DSA_PUBLIC_MAGIC_V2 || hdr.KeySize*8 != uint32(l) {
if hdr.Magic != bcrypt.DSA_PUBLIC_MAGIC_V2 || hdr.KeySize*8 != uint32(L) {
return DSAParameters{}, errors.New("crypto/dsa: exported key is corrupted")
}
consumeBigInt := func(size uint32) BigInt {
b := data[:size]
data = data[size:]
return b
}
// Discard the seed, crypto/dsa doesn't use it.
consumeBigInt(hdr.SeedLength)
return DSAParameters{
S: consumeBigInt(hdr.SeedLength),
Q: consumeBigInt(hdr.GroupSize),
P: consumeBigInt(hdr.KeySize),
G: consumeBigInt(hdr.KeySize),
}, nil
}

type DSAPrivateKey struct {
hkey bcrypt.KEY_HANDLE
}

func (k *DSAPrivateKey) finalize() {
bcrypt.DestroyKey(k.hkey)
}

func GenerateKey(params DSAParameters) (*DSAPrivateKey, error) {
h, err := loadDSA()
if err != nil {
return nil, err
}
// setDSAParameter sets the DSA parameters for the given key.
func setDSAParameter(hkey bcrypt.KEY_HANDLE, params DSAParameters) error {
keySize := uint32(len(params.P))
groupSize := uint32(len(params.Q))
seedSize := uint32(len(params.S))
var hkey bcrypt.KEY_HANDLE
if err := bcrypt.GenerateKeyPair(h.handle, &hkey, keySize*8, 0); err != nil {
return nil, err
}
var blob []byte
var idx int
appendBigInt := func(b BigInt) {
copy(blob[idx:], b[:])
idx += len(b)
}
if keySize*8 <= 1024 {
blob = make([]byte, sizeOfDSAParamsHeader+keySize*2)
hdr := bcrypt.DSA_PARAMETER_HEADER{
Length: uint32(len(blob)),
Magic: bcrypt.DSA_PARAMETERS_MAGIC_V2,
Magic: bcrypt.DSA_PARAMETERS_MAGIC,
KeySize: keySize,
//Count: ,
Count: [4]byte{0xff, 0xff, 0xff, 0xff}, // disables verification, we don't have the seed.
}
copy(hdr.Seed[:], params.S[:])
copy(hdr.Q[:], params.Q[:])
copy(blob, (*(*[sizeOfDSAParamsHeader]byte)(unsafe.Pointer(&hdr)))[:])
i := int(sizeOfDSAParamsHeader)
copy(blob[i:], params.P[:])
i += len(params.P)
copy(blob[i:], params.G[:])
idx = int(sizeOfDSAParamsHeader)
appendBigInt(params.P)
appendBigInt(params.G)
} else {
blob = make([]byte, sizeOfDSAParamsV2Header+keySize*2+groupSize+seedSize)
blob = make([]byte, sizeOfDSAParamsV2Header+2*keySize+2*groupSize)
hdr := bcrypt.DSA_PARAMETER_HEADER_V2{
Length: uint32(len(blob)),
Magic: bcrypt.DSA_PARAMETERS_MAGIC_V2,
KeySize: keySize,
GroupSize: groupSize,
HashAlgorithm: bcrypt.DSA_HASH_ALGORITHM_SHA256,
StandardVersion: bcrypt.DSA_FIPS186_3,
SeedLength: seedSize,
//Count: ,
SeedLength: groupSize, // crypto/dsa doesn't use the seed, but it's size can't be zero.
Count: [4]byte{0xff, 0xff, 0xff, 0xff}, // disables verification, we don't have the seed.
}
copy(blob, (*(*[sizeOfDSAParamsV2Header]byte)(unsafe.Pointer(&hdr)))[:])
i := int(sizeOfDSAParamsV2Header)
copy(blob[i:], params.S[:])
i += len(params.S)
copy(blob[i:], params.Q[:])
i += len(params.Q)
copy(blob[i:], params.P[:])
i += len(params.P)
copy(blob[i:], params.G[:])
idx = int(sizeOfDSAParamsV2Header + groupSize) // skip the seed
appendBigInt(params.Q)
appendBigInt(params.P)
appendBigInt(params.G)

}
// TODO: This still not works...
if err := bcrypt.SetProperty(bcrypt.HANDLE(hkey), utf16PtrFromString(bcrypt.DSA_PARAMETERS), blob, 0); err != nil {
bcrypt.DestroyKey(hkey)
return nil, err
}
if err := bcrypt.FinalizeKeyPair(hkey, 0); err != nil {
bcrypt.DestroyKey(hkey)
return nil, err
}
k := &DSAPrivateKey{hkey}
runtime.SetFinalizer(k, (*DSAPrivateKey).finalize)
return k, nil
return bcrypt.SetProperty(bcrypt.HANDLE(hkey), utf16PtrFromString(bcrypt.DSA_PARAMETERS), blob, 0)
}
2 changes: 1 addition & 1 deletion cng/dsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func testParameterGeneration(t *testing.T, L, N int) {
t.Errorf("%d-%d: invalid generator", L, N)
}

_, err = cng.GenerateKey(params)
_, err = cng.GenerateDSAKey(params)
if err != nil {
t.Errorf("error generating key: %s", err)
return
Expand Down
2 changes: 1 addition & 1 deletion cng/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const (
sizeOfDSABlobHeader = uint32(unsafe.Sizeof(bcrypt.DSA_KEY_BLOB{}))
sizeOfDSAV2BlobHeader = uint32(unsafe.Sizeof(bcrypt.DSA_KEY_BLOB_V2{}))
sizeOfDSAParamsHeader = uint32(unsafe.Sizeof(bcrypt.DSA_PARAMETER_HEADER{}))
sizeOfDSAParamsV2Header = uint32(unsafe.Sizeof(bcrypt.DSA_PARAMETER_HEADER{}))
sizeOfDSAParamsV2Header = uint32(unsafe.Sizeof(bcrypt.DSA_PARAMETER_HEADER_V2{}))
)

// exporDSAKey exports hkey into a bcrypt.DSA_KEY_BLOB header and data.
Expand Down

0 comments on commit c4ea81d

Please sign in to comment.