예제 #1
0
        public override DSAParameters ExportParameters(bool includePrivateParameters)
        {
            byte[] dsaBlob = ExportKeyBlob(includePrivateParameters);

            KeyBlobMagicNumber magic = (KeyBlobMagicNumber)BitConverter.ToInt32(dsaBlob, 0);

            // Check the magic value in the key blob header. If the blob does not have the required magic,
            // then throw a CryptographicException.
            CheckMagicValueOfKey(magic, includePrivateParameters);

            unsafe
            {
                DSAParameters dsaParams = default;

                fixed(byte *pDsaBlob = dsaBlob)
                {
                    int offset;

                    if (magic == KeyBlobMagicNumber.BCRYPT_DSA_PUBLIC_MAGIC || magic == KeyBlobMagicNumber.BCRYPT_DSA_PRIVATE_MAGIC)
                    {
                        if (dsaBlob.Length < sizeof(BCRYPT_DSA_KEY_BLOB))
                        {
                            throw ErrorCode.E_FAIL.ToCryptographicException();
                        }

                        BCRYPT_DSA_KEY_BLOB *pBcryptBlob = (BCRYPT_DSA_KEY_BLOB *)pDsaBlob;
                        // We now have a buffer laid out as follows:
                        //     BCRYPT_DSA_KEY_BLOB  header
                        //     byte[cbKey]               P
                        //     byte[cbKey]               G
                        //     byte[cbKey]               Y
                        //     -- Private only --
                        //     byte[Sha1HashOutputSize]  X

                        offset = sizeof(KeyBlobMagicNumber) + sizeof(int); // skip Magic and cbKey

                        // Read out a (V1) BCRYPT_DSA_KEY_BLOB structure.
                        dsaParams.Counter = BinaryPrimitives.ReadInt32BigEndian(Interop.BCrypt.Consume(dsaBlob, ref offset, 4));
                        dsaParams.Seed    = Interop.BCrypt.Consume(dsaBlob, ref offset, Sha1HashOutputSize);
                        dsaParams.Q       = Interop.BCrypt.Consume(dsaBlob, ref offset, Sha1HashOutputSize);

                        Debug.Assert(offset == sizeof(BCRYPT_DSA_KEY_BLOB), $"Expected offset = sizeof(BCRYPT_DSA_KEY_BLOB), got {offset} != {sizeof(BCRYPT_DSA_KEY_BLOB)}");
                        dsaParams.P = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbKey);
                        dsaParams.G = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbKey);
                        dsaParams.Y = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbKey);
                        if (includePrivateParameters)
                        {
                            dsaParams.X = Interop.BCrypt.Consume(dsaBlob, ref offset, Sha1HashOutputSize);
                        }
                    }
                    else
                    {
                        Debug.Assert(magic == KeyBlobMagicNumber.BCRYPT_DSA_PUBLIC_MAGIC_V2 || magic == KeyBlobMagicNumber.BCRYPT_DSA_PRIVATE_MAGIC_V2);

                        if (dsaBlob.Length < sizeof(BCRYPT_DSA_KEY_BLOB_V2))
                        {
                            throw ErrorCode.E_FAIL.ToCryptographicException();
                        }

                        BCRYPT_DSA_KEY_BLOB_V2 *pBcryptBlob = (BCRYPT_DSA_KEY_BLOB_V2 *)pDsaBlob;
                        // We now have a buffer laid out as follows:
                        //     BCRYPT_DSA_KEY_BLOB_V2  header
                        //     byte[cbSeedLength]      Seed
                        //     byte[cbGroupSize]       Q
                        //     byte[cbKey]             P
                        //     byte[cbKey]             G
                        //     byte[cbKey]             Y
                        //     -- Private only --
                        //     byte[cbGroupSize]       X

                        offset = sizeof(BCRYPT_DSA_KEY_BLOB_V2) - 4; //skip to Count[4]

                        // Read out a BCRYPT_DSA_KEY_BLOB_V2 structure.
                        dsaParams.Counter = BinaryPrimitives.ReadInt32BigEndian(Interop.BCrypt.Consume(dsaBlob, ref offset, 4));

                        Debug.Assert(offset == sizeof(BCRYPT_DSA_KEY_BLOB_V2), $"Expected offset = sizeof(BCRYPT_DSA_KEY_BLOB_V2), got {offset} != {sizeof(BCRYPT_DSA_KEY_BLOB_V2)}");

                        dsaParams.Seed = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbSeedLength);
                        dsaParams.Q    = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbGroupSize);
                        dsaParams.P    = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbKey);
                        dsaParams.G    = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbKey);
                        dsaParams.Y    = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbKey);
                        if (includePrivateParameters)
                        {
                            dsaParams.X = Interop.BCrypt.Consume(dsaBlob, ref offset, pBcryptBlob->cbGroupSize);
                        }
                    }

                    // If no counter/seed information is present, normalize Counter and Seed to 0/null to maintain parity with the CAPI version of DSA.
                    if (dsaParams.Counter == -1)
                    {
                        dsaParams.Counter = 0;
                        dsaParams.Seed    = null;
                    }

                    Debug.Assert(offset == dsaBlob.Length, $"Expected offset = dsaBlob.Length, got {offset} != {dsaBlob.Length}");

                    return(dsaParams);
                }
            }
        }
예제 #2
0
        private static unsafe void GenerateV1DsaBlob(out byte[] blob, DSAParameters parameters, int cbKey, bool includePrivate)
        {
            // We need to build a key blob structured as follows:
            //
            //     BCRYPT_DSA_KEY_BLOB       header
            //     byte[cbKey]               P
            //     byte[cbKey]               G
            //     byte[cbKey]               Y
            //     -- Private only --
            //     byte[Sha1HashOutputSize]  X

            int blobSize =
                sizeof(BCRYPT_DSA_KEY_BLOB) +
                cbKey +
                cbKey +
                cbKey;

            if (includePrivate)
            {
                blobSize += Sha1HashOutputSize;
            }

            blob = new byte[blobSize];
            fixed(byte *pDsaBlob = &blob[0])
            {
                // Build the header
                BCRYPT_DSA_KEY_BLOB *pBcryptBlob = (BCRYPT_DSA_KEY_BLOB *)pDsaBlob;

                pBcryptBlob->Magic = includePrivate ? KeyBlobMagicNumber.BCRYPT_DSA_PRIVATE_MAGIC : KeyBlobMagicNumber.BCRYPT_DSA_PUBLIC_MAGIC;
                pBcryptBlob->cbKey = cbKey;

                int offset = sizeof(KeyBlobMagicNumber) + sizeof(int); // skip Magic and cbKey

                if (parameters.Seed != null)
                {
                    // The Seed length is hardcoded into BCRYPT_DSA_KEY_BLOB, so check it now we can give a nicer error message.
                    if (parameters.Seed.Length != Sha1HashOutputSize)
                    {
                        throw new ArgumentException(SR.Cryptography_InvalidDsaParameters_SeedRestriction_ShortKey);
                    }

                    Interop.BCrypt.EmitBigEndian(blob, ref offset, parameters.Counter);
                    Interop.BCrypt.Emit(blob, ref offset, parameters.Seed);
                }
                else
                {
                    // If Seed is not present, back fill both counter and seed with 0xff. Do not use parameters.Counter as CNG is more strict than CAPI and will reject
                    // anything other than 0xffffffff. That could complicate efforts to switch usage of DSACryptoServiceProvider to DSACng.
                    Interop.BCrypt.EmitByte(blob, ref offset, 0xff, Sha1HashOutputSize + sizeof(int));
                }

                // The Q length is hardcoded into BCRYPT_DSA_KEY_BLOB, so check it now we can give a nicer error message.
                if (parameters.Q !.Length != Sha1HashOutputSize)
                {
                    throw new ArgumentException(SR.Cryptography_InvalidDsaParameters_QRestriction_ShortKey);
                }

                Interop.BCrypt.Emit(blob, ref offset, parameters.Q);

                Debug.Assert(offset == sizeof(BCRYPT_DSA_KEY_BLOB), $"Expected offset = sizeof(BCRYPT_DSA_KEY_BLOB), got {offset} != {sizeof(BCRYPT_DSA_KEY_BLOB)}");

                Interop.BCrypt.Emit(blob, ref offset, parameters.P !);
                Interop.BCrypt.Emit(blob, ref offset, parameters.G !);
                Interop.BCrypt.Emit(blob, ref offset, parameters.Y !);
                if (includePrivate)
                {
                    Interop.BCrypt.Emit(blob, ref offset, parameters.X !);
                }

                Debug.Assert(offset == blobSize, $"Expected offset = blobSize, got {offset} != {blobSize}");
            }
        }