internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBIts)
        {
            SecKeyPair keys = GetOrGenerateKeys(keySizeInBIts);

            SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;

            if (keyHandle == null)
            {
                throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
            }

            DerSequenceReader keyReader  = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
            ECParameters      parameters = new ECParameters();

            if (includePrivateParameters)
            {
                keyReader.ReadPkcs8Blob(ref parameters);
            }
            else
            {
                keyReader.ReadSubjectPublicKeyInfo(ref parameters);
            }

            int size = AsymmetricAlgorithmHelpers.BitsToBytes(keySizeInBIts);

            KeyBlobHelpers.PadOrTrim(ref parameters.Q.X, size);
            KeyBlobHelpers.PadOrTrim(ref parameters.Q.Y, size);

            if (includePrivateParameters)
            {
                KeyBlobHelpers.PadOrTrim(ref parameters.D, size);
            }

            return(parameters);
        }
Example #2
0
        /// <summary>
        ///   Gets the largest size, in bytes, for a signature produced by this key in the indicated format.
        /// </summary>
        /// <param name="signatureFormat">The encoding format for a signature.</param>
        /// <returns>
        ///   The largest size, in bytes, for a signature produced by this key in the indicated format.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        ///   <paramref name="signatureFormat"/> is not a known format.
        /// </exception>
        public int GetMaxSignatureSize(DSASignatureFormat signatureFormat)
        {
            int fieldSizeBits = KeySize;

            if (fieldSizeBits == 0)
            {
                // Coerce the key/key-size into existence
                ExportParameters(false);

                fieldSizeBits = KeySize;

                // This implementation of ECDsa doesn't set KeySize, we can't
                if (fieldSizeBits == 0)
                {
                    throw new NotSupportedException(SR.Cryptography_InvalidKeySize);
                }
            }

            switch (signatureFormat)
            {
            case DSASignatureFormat.IeeeP1363FixedFieldConcatenation:
                return(AsymmetricAlgorithmHelpers.BitsToBytes(fieldSizeBits) * 2);

            case DSASignatureFormat.Rfc3279DerSequence:
                return(AsymmetricAlgorithmHelpers.GetMaxDerSignatureSize(fieldSizeBits));

            default:
                throw new ArgumentOutOfRangeException(nameof(signatureFormat));
            }
        }
Example #3
0
        public override bool VerifyHash(byte[] hash, byte[] signature)
        {
            if (hash == null)
            {
                throw new ArgumentNullException(nameof(hash));
            }
            if (signature == null)
            {
                throw new ArgumentNullException(nameof(signature));
            }

            // The signature format for .NET is r.Concat(s). Each of r and s are of length BitsToBytes(KeySize), even
            // when they would have leading zeroes.  If it's the correct size, then we need to encode it from
            // r.Concat(s) to SEQUENCE(INTEGER(r), INTEGER(s)), because that's the format that OpenSSL expects.
            int expectedBytes = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize);

            if (signature.Length != expectedBytes)
            {
                // The input isn't of the right length, so we can't sensibly re-encode it.
                return(false);
            }

            byte[] openSslFormat = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature);

            SafeEcKeyHandle key          = _key.Value;
            int             verifyResult = Interop.Crypto.EcDsaVerify(hash, hash.Length, openSslFormat, openSslFormat.Length, key);

            return(verifyResult == 1);
        }
        private ILiteSymmetricCipher CreateLiteSymmetricCipher(
            ReadOnlySpan <byte> key,
            ReadOnlySpan <byte> iv,
            bool encrypting,
            PaddingMode padding,
            CipherMode mode,
            int feedbackSizeInBits)
        {
            ValidateFeedbackSize(mode, feedbackSizeInBits);

            if (!iv.IsEmpty && iv.Length != AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize))
            {
                throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof(iv));
            }

            if (mode.UsesIv() && iv.IsEmpty)
            {
                throw new CryptographicException(SR.Cryptography_MissingIV);
            }

            byte[] processedKey     = CopyAndValidateKey(key);
            int    blockSizeInBytes = AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize);
            SafeAlgorithmHandle algorithmModeHandle = _outer.GetEphemeralModeHandle(mode, feedbackSizeInBits);

            return(new BasicSymmetricCipherLiteBCrypt(
                       algorithmModeHandle,
                       mode,
                       blockSizeInBytes,
                       _outer.GetPaddingSize(mode, feedbackSizeInBits),
                       processedKey,
                       ownsParentHandle: false,
                       iv,
                       encrypting));
        }
Example #5
0
        public override bool TrySignHash(ReadOnlySpan <byte> hash, Span <byte> destination, out int bytesWritten)
#endif
        {
            ThrowIfDisposed();
            SafeEcKeyHandle key = _key.Value;

            int         signatureLength = Interop.Crypto.EcDsaSize(key);
            Span <byte> signDestination = stackalloc byte[SignatureStackBufSize];

#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
            if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation)
            {
#endif
            int encodedSize = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize);

            if (destination.Length < encodedSize)
            {
                bytesWritten = 0;
                return(false);
            }

            ReadOnlySpan <byte> derSignature = SignHash(hash, signDestination, signatureLength, key);
            bytesWritten = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, KeySize, destination);
            Debug.Assert(bytesWritten == encodedSize);
            return(true);

#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
        }

        else if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence)
        {
            if (destination.Length >= signatureLength)
            {
                signDestination = destination;
            }
            else if (signatureLength > signDestination.Length)
            {
                Debug.Fail($"Stack-based signDestination is insufficient ({signatureLength} needed)");
                bytesWritten = 0;
                return(false);
            }

            ReadOnlySpan <byte> derSignature = SignHash(hash, signDestination, signatureLength, key);

            if (destination == signDestination)
            {
                bytesWritten = derSignature.Length;
                return(true);
            }

            return(Helpers.TryCopyToDestination(derSignature, destination, out bytesWritten));
        }
        else
        {
            throw new ArgumentOutOfRangeException(nameof(signatureFormat));
        }
#endif
        }
Example #6
0
        public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature)
#endif
        {
            ThrowIfDisposed();

            Span <byte>         derSignature = stackalloc byte[SignatureStackBufSize];
            ReadOnlySpan <byte> toVerify     = derSignature;

#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
            if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation)
            {
#endif
            // The signature format for .NET is r.Concat(s). Each of r and s are of length BitsToBytes(KeySize), even
            // when they would have leading zeroes.  If it's the correct size, then we need to encode it from
            // r.Concat(s) to SEQUENCE(INTEGER(r), INTEGER(s)), because that's the format that OpenSSL expects.
            int expectedBytes = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize);
            if (signature.Length != expectedBytes)
            {
                // The input isn't of the right length, so we can't sensibly re-encode it.
                return(false);
            }

            if (AsymmetricAlgorithmHelpers.TryConvertIeee1363ToDer(signature, derSignature, out int derSize))
            {
                toVerify = derSignature.Slice(0, derSize);
            }
            else
            {
                toVerify = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature);
            }
#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
        }

        else if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence)
        {
            toVerify = signature;
        }
        else
        {
            Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}");
            throw new CryptographicException(
                      SR.Cryptography_UnknownSignatureFormat,
                      signatureFormat.ToString());
        }
#endif

            SafeEcKeyHandle key = _key.Value;
            int verifyResult    = Interop.Crypto.EcDsaVerify(hash, toVerify, key);
            return(verifyResult == 1);
        }
Example #7
0
        private UniversalCryptoTransform CreateEphemeralCryptoTransformCore(byte[] key, byte[]?iv, bool encrypting, PaddingMode padding, CipherMode mode, int feedbackSizeInBits)
        {
            int blockSizeInBytes = AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize);
            SafeAlgorithmHandle algorithmModeHandle = _outer.GetEphemeralModeHandle(mode, feedbackSizeInBits);

            BasicSymmetricCipher cipher = new BasicSymmetricCipherBCrypt(
                algorithmModeHandle,
                mode,
                blockSizeInBytes,
                _outer.GetPaddingSize(mode, feedbackSizeInBits),
                key,
                ownsParentHandle: false,
                iv,
                encrypting);

            return(UniversalCryptoTransform.Create(padding, cipher, encrypting));
        }
Example #8
0
            public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature)
            {
                // The signature format for .NET is r.Concat(s). Each of r and s are of length BitsToBytes(KeySize), even
                // when they would have leading zeroes.  If it's the correct size, then we need to encode it from
                // r.Concat(s) to SEQUENCE(INTEGER(r), INTEGER(s)), because that's the format that OpenSSL expects.
                int expectedBytes = 2 * AsymmetricAlgorithmHelpers.BitsToBytes(KeySize);

                if (signature.Length != expectedBytes)
                {
                    // The input isn't of the right length, so we can't sensibly re-encode it.
                    return(false);
                }

                return(Interop.AppleCrypto.VerifySignature(
                           GetKeys().PublicKey,
                           hash,
                           AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature)));
            }
Example #9
0
        private UniversalCryptoTransform CreatePersistedCryptoTransformCore(Func <CngKey> cngKeyFactory, byte[]?iv, bool encrypting, PaddingMode padding, CipherMode mode, int feedbackSizeInBits)
        {
            // note: iv is guaranteed to be cloned before this method, so no need to clone it again

            ValidateFeedbackSize(mode, feedbackSizeInBits);
            Debug.Assert(mode == CipherMode.CFB ? feedbackSizeInBits == 8 : true);

            int blockSizeInBytes        = AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize);
            BasicSymmetricCipher cipher = new BasicSymmetricCipherNCrypt(
                cngKeyFactory,
                mode,
                blockSizeInBytes,
                iv,
                encrypting,
                _outer.GetPaddingSize(mode, feedbackSizeInBits));

            return(UniversalCryptoTransform.Create(padding, cipher, encrypting));
        }
        private UniversalCryptoTransform CreateCryptoTransform(byte[] rgbKey, byte[]?rgbIV, bool encrypting, PaddingMode padding, CipherMode mode, int feedbackSizeInBits)
        {
            ArgumentNullException.ThrowIfNull(rgbKey);

            ValidateFeedbackSize(mode, feedbackSizeInBits);
            byte[] key = CopyAndValidateKey(rgbKey);

            if (rgbIV != null && rgbIV.Length != AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize))
            {
                throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof(rgbIV));
            }

            // CloneByteArray is null-preserving. So even when GetCipherIv returns null the iv variable
            // is correct, and detached from the input parameter.
            byte[]? iv = mode.GetCipherIv(rgbIV).CloneByteArray();

            return(CreateEphemeralCryptoTransformCore(key, iv, encrypting, padding, mode, feedbackSizeInBits));
        }
        private ILiteSymmetricCipher CreatePersistedLiteSymmetricCipher(
            Func <CngKey> cngKeyFactory,
            ReadOnlySpan <byte> iv,
            bool encrypting,
            PaddingMode padding,
            CipherMode mode,
            int feedbackSizeInBits)
        {
            ValidateFeedbackSize(mode, feedbackSizeInBits);
            Debug.Assert(mode == CipherMode.CFB ? feedbackSizeInBits == 8 : true);
            int blockSizeInBytes = AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize);

            return(new BasicSymmetricCipherLiteNCrypt(
                       cngKeyFactory,
                       mode,
                       blockSizeInBytes,
                       iv,
                       encrypting,
                       _outer.GetPaddingSize(mode, feedbackSizeInBits)));
        }
Example #12
0
        private UniversalCryptoTransform CreateCryptoTransform(byte[] rgbKey, byte[]?rgbIV, bool encrypting, PaddingMode padding, CipherMode mode, int feedbackSizeInBits)
        {
            if (rgbKey == null)
            {
                throw new ArgumentNullException(nameof(rgbKey));
            }

            ValidateFeedbackSize(mode, feedbackSizeInBits);

            byte[] key = rgbKey.CloneByteArray();

            long keySize = key.Length * (long)BitsPerByte;

            if (keySize > int.MaxValue || !((int)keySize).IsLegalSize(_outer.LegalKeySizes))
            {
                throw new ArgumentException(SR.Cryptography_InvalidKeySize, nameof(rgbKey));
            }

            if (_outer.IsWeakKey(key))
            {
                throw new CryptographicException(
                          SR.Format(
                              SR.Cryptography_InvalidKey_Weak,
                              _outer.GetNCryptAlgorithmIdentifier()));
            }

            if (rgbIV != null && rgbIV.Length != AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize))
            {
                throw new ArgumentException(SR.Cryptography_InvalidIVSize, nameof(rgbIV));
            }

            // CloneByteArray is null-preserving. So even when GetCipherIv returns null the iv variable
            // is correct, and detached from the input parameter.
            byte[]? iv = mode.GetCipherIv(rgbIV).CloneByteArray();

            key = _outer.PreprocessKey(key);

            return(CreateEphemeralCryptoTransformCore(key, iv, encrypting, padding, mode, feedbackSizeInBits));
        }
Example #13
0
 public void GenerateKey()
 {
     byte[] key = Helpers.GenerateRandom(AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BaseKeySize));
     SetKey(key);
 }
Example #14
0
 public void GenerateIV()
 {
     byte[] iv = Helpers.GenerateRandom(AsymmetricAlgorithmHelpers.BitsToBytes(_outer.BlockSize));
     _outer.IV = iv;
 }
Example #15
0
            /// <summary>
            /// Get the secret agreement generated between two parties
            /// </summary>
            private byte[]? DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash?hasher)
            {
                Debug.Assert(otherPartyPublicKey != null);

                // Ensure that this ECDH object contains a private key by attempting a parameter export
                // which will throw an OpenSslCryptoException if no private key is available
                ECParameters thisKeyExplicit             = ExportExplicitParameters(true);
                bool         thisIsNamed                 = Interop.AndroidCrypto.EcKeyHasCurveName(_key.Value);
                ECDiffieHellmanAndroidPublicKey?otherKey = otherPartyPublicKey as ECDiffieHellmanAndroidPublicKey;
                bool disposeOtherKey = false;

                if (otherKey == null)
                {
                    disposeOtherKey = true;

                    ECParameters otherParameters =
                        thisIsNamed
                            ? otherPartyPublicKey.ExportParameters()
                            : otherPartyPublicKey.ExportExplicitParameters();

                    otherKey = new ECDiffieHellmanAndroidPublicKey(otherParameters);
                }

                bool otherIsNamed = otherKey.HasCurveName;

                SafeEcKeyHandle?ourKey   = null;
                SafeEcKeyHandle?theirKey = null;

                byte[]? rented = null;
                // Calculate secretLength in bytes.
                int secretLength = AsymmetricAlgorithmHelpers.BitsToBytes(KeySize);

                try
                {
                    if (otherKey.KeySize != KeySize)
                    {
                        throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey));
                    }

                    if (otherIsNamed == thisIsNamed)
                    {
                        ourKey   = _key.UpRefKeyHandle();
                        theirKey = otherKey.DuplicateKeyHandle();
                    }
                    else if (otherIsNamed)
                    {
                        ourKey = _key.UpRefKeyHandle();

                        using (ECAndroid tmp = new ECAndroid(otherKey.ExportExplicitParameters()))
                        {
                            theirKey = tmp.UpRefKeyHandle();
                        }
                    }
                    else
                    {
                        using (ECAndroid tmp = new ECAndroid(thisKeyExplicit))
                        {
                            ourKey = tmp.UpRefKeyHandle();
                        }

                        theirKey = otherKey.DuplicateKeyHandle();
                    }

                    // Indicate that secret can hold stackallocs from nested scopes
                    Span <byte> secret = stackalloc byte[0];

                    // Arbitrary limit. But it covers secp521r1, which is the biggest common case.
                    const int StackAllocMax = 66;

                    if (secretLength > StackAllocMax)
                    {
                        rented = CryptoPool.Rent(secretLength);
                        secret = new Span <byte>(rented, 0, secretLength);
                    }
                    else
                    {
                        secret = stackalloc byte[secretLength];
                    }

                    if (!Interop.AndroidCrypto.EcdhDeriveKey(ourKey, theirKey, secret, out int usedBufferLength))
                    {
                        throw new CryptographicException();
                    }

                    Debug.Assert(secretLength == usedBufferLength, $"Expected secret length {secretLength} does not match actual secret length {usedBufferLength}.");

                    if (hasher == null)
                    {
                        return(secret.ToArray());
                    }
                    else
                    {
                        hasher.AppendData(secret);
                        return(null);
                    }
                }
                finally
                {
                    theirKey?.Dispose();
                    ourKey?.Dispose();

                    if (disposeOtherKey)
                    {
                        otherKey.Dispose();
                    }

                    if (rented != null)
                    {
                        CryptoPool.Return(rented, secretLength);
                    }
                }
            }