/// <summary>
        /// Performs an encryption or decryption operation.
        /// </summary>
        /// <param name="cipherFunction">The delegate that will actually perform the cryptographic operation.</param>
        /// <returns>A buffer containing the result of the cryptographic operation.</returns>
        protected unsafe byte[] EncryptOrDecrypt(EncryptOrDecryptFunction cipherFunction)
        {
            Requires.NotNull(cipherFunction, nameof(cipherFunction));

            if (this.EncryptionPadding.Value == AsymmetricEncryptionPadding.None)
            {
                return(cipherFunction(null, NCryptEncryptFlags.NCRYPT_NO_PADDING_FLAG));
            }

            switch (this.EncryptionPadding.Value)
            {
            case AsymmetricEncryptionPadding.Pkcs1:
                return(cipherFunction(null, NCryptEncryptFlags.NCRYPT_PAD_PKCS1_FLAG));

            case AsymmetricEncryptionPadding.Oaep:
                fixed(char *hashAlgorithmNamePointer = &HashAlgorithmProviderFactory.GetHashAlgorithmName(this.SignatureHash.Value).ToCharArrayWithNullTerminator()[0])
                {
                    var paddingInfo = new BCrypt.BCRYPT_OAEP_PADDING_INFO
                    {
                        pszAlgId = hashAlgorithmNamePointer,
                        pbLabel  = null,
                        cbLabel  = 0,
                    };

                    return(cipherFunction(&paddingInfo, NCryptEncryptFlags.NCRYPT_PAD_OAEP_FLAG));
                }

            default:
                throw new NotImplementedException();
            }
        }
Example #2
0
        /// <summary>
        /// Gets the OID (or name) for a given hash algorithm.
        /// </summary>
        /// <param name="algorithm">The algorithm.</param>
        /// <returns>A non-empty string.</returns>
        internal static string GetHashAlgorithmOID(AsymmetricAlgorithm algorithm)
        {
            string algorithmName = HashAlgorithmProviderFactory.GetHashAlgorithmName(AsymmetricKeyAlgorithmProviderFactory.GetHashAlgorithmEnum(algorithm));

#if SILVERLIGHT
            // Windows Phone 8.0 and Silverlight both are missing the
            // CryptoConfig type. But that's ok since both platforms
            // accept the algorithm name directly as well as the OID
            // which we can't easily get to.
            return(algorithmName);
#else
            // Mono requires the OID, so we get it when we can.
            return(Platform.CryptoConfig.MapNameToOID(algorithmName));
#endif
        }
        /// <summary>Creates the hash algorithm.</summary>
        /// <param name="algorithm">The algorithm.</param>
        /// <returns>A platform-specific hash algorithm.</returns>
        internal static Platform.HashAlgorithm CreateHashAlgorithm(HashAlgorithm algorithm)
        {
#if SILVERLIGHT
            switch (algorithm)
            {
            case HashAlgorithm.Sha1:
                return(new Platform.SHA1Managed());

            case HashAlgorithm.Sha256:
                return(new Platform.SHA256Managed());

            default:
                throw new NotSupportedException();
            }
#else
            string algorithmName = HashAlgorithmProviderFactory.GetHashAlgorithmName(algorithm);
            return(Platform.HashAlgorithm.Create(algorithmName));
#endif
        }
        /// <summary>
        /// Gets the string to pass to <see cref="Signature.GetInstance(string)"/>
        /// for a given algorithm.
        /// </summary>
        /// <param name="algorithm">The algorithm.</param>
        /// <returns>A non-empty string.</returns>
        /// <exception cref="System.NotSupportedException">Thrown if the algorithm is not supported.</exception>
        private static string GetSignatureName(AsymmetricAlgorithm algorithm)
        {
            string hashName = HashAlgorithmProviderFactory.GetHashAlgorithmName(AsymmetricKeyAlgorithmProviderFactory.GetHashAlgorithmEnum(algorithm));

            switch (algorithm)
            {
            case AsymmetricAlgorithm.RsaSignPkcs1Sha1:
            case AsymmetricAlgorithm.RsaSignPkcs1Sha256:
            case AsymmetricAlgorithm.RsaSignPkcs1Sha384:
            case AsymmetricAlgorithm.RsaSignPkcs1Sha512:
                return(hashName + "withRSA");

            case AsymmetricAlgorithm.RsaSignPssSha1:
            case AsymmetricAlgorithm.RsaSignPssSha256:
            case AsymmetricAlgorithm.RsaSignPssSha384:
            case AsymmetricAlgorithm.RsaSignPssSha512:
            default:
                throw new NotSupportedException();
            }
        }
        /// <summary>
        /// Performs a signing or verification operation.
        /// </summary>
        /// <param name="action">The delegate that will actually perform the cryptographic operation.</param>
        /// <remarks>
        /// This method should not throw an error when verifying a signature and
        /// the signature is invalid. Rather, the delegate should retain the result of
        /// verification and the caller of this method should share that closure and
        /// return the result.
        /// </remarks>
        protected unsafe void SignOrVerify(SignOrVerifyAction action)
        {
            Requires.NotNull(action, nameof(action));

            if (this.SignaturePadding.Value == AsymmetricSignaturePadding.None)
            {
                action(null, NCryptSignHashFlags.None);
            }
            else
            {
                char[] hashAlgorithmName = HashAlgorithmProviderFactory.GetHashAlgorithmName(this.SignatureHash.Value).ToCharArrayWithNullTerminator();
                fixed(char *hashAlgorithmNamePointer = &hashAlgorithmName[0])
                {
                    switch (this.SignaturePadding.Value)
                    {
                    case AsymmetricSignaturePadding.Pkcs1:
                        var pkcs1PaddingInfo = new BCrypt.BCRYPT_PKCS1_PADDING_INFO
                        {
                            pszAlgId = hashAlgorithmNamePointer,
                        };
                        action(&pkcs1PaddingInfo, NCryptSignHashFlags.BCRYPT_PAD_PKCS1);
                        break;

                    case AsymmetricSignaturePadding.Pss:
                        var pssPaddingInfo = new BCrypt.BCRYPT_PSS_PADDING_INFO
                        {
                            pszAlgId = hashAlgorithmNamePointer,
                            cbSalt   = hashAlgorithmName.Length,
                        };
                        action(&pssPaddingInfo, NCryptSignHashFlags.BCRYPT_PAD_PSS);
                        break;

                    default:
                        throw new NotImplementedException();
                    }
                }
            }
        }
Example #6
0
        /// <inheritdoc />
        public byte[] DeriveKeyMaterial(IECDiffieHellmanPublicKey otherParty)
        {
            Requires.NotNull(otherParty, nameof(otherParty));

            var publicKey = (ECDiffieHellmanPublicKey)otherParty;

            using (var secret = BCryptSecretAgreement(this.PlatformKey, publicKey.Key))
            {
                IntPtr hashAlgorithmPtr = IntPtr.Zero;
                try
                {
                    string hashAlgorithmString = HashAlgorithmProviderFactory.GetHashAlgorithmName(this.HashAlgorithm);
                    try
                    {
                    }
                    finally
                    {
                        // Do this in a finally so that ThreadAbortException doesn't interrupt the
                        // assignment of a successfully allocated pointer.
                        hashAlgorithmPtr = Marshal.StringToHGlobalUni(hashAlgorithmString);
                    }

                    var parameters = new List <BCryptBuffer>();
                    parameters.Add(new BCryptBuffer
                    {
                        cbBuffer        = (hashAlgorithmString.Length + 1) * sizeof(char),
                        BufferType      = BufferType.KDF_HASH_ALGORITHM,
                        pvBuffer_IntPtr = hashAlgorithmPtr,
                    });

                    const string kdf = KeyDerivationFunctions.BCRYPT_KDF_HASH;
                    unsafe
                    {
                        fixed(BCryptBuffer *pParameters = parameters.ToArray())
                        {
                            var parameterDesc = new BCryptBufferDesc
                            {
                                ulVersion = 0,
                                cBuffers  = parameters.Count,
                                pBuffers  = pParameters,
                            };

                            int secretLength;

                            BCryptDeriveKey(
                                secret,
                                kdf,
                                ref parameterDesc,
                                null,
                                0,
                                out secretLength,
                                BCryptDeriveKeyFlags.KDF_USE_SECRET_AS_HMAC_KEY_FLAG).ThrowOnError();

                            byte[] derivedKey = new byte[secretLength];
                            BCryptDeriveKey(
                                secret,
                                kdf,
                                ref parameterDesc,
                                derivedKey,
                                derivedKey.Length,
                                out secretLength,
                                0).ThrowOnError();
                            Assumes.True(secretLength == derivedKey.Length);
                            return(derivedKey);
                        }
                    }
                }
                finally
                {
                    if (hashAlgorithmPtr != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(hashAlgorithmPtr);
                    }
                }
            }
        }
Example #7
0
        /// <summary>
        /// Creates the hash algorithm.
        /// </summary>
        /// <param name="algorithm">The algorithm.</param>
        /// <returns>
        /// A platform-specific hash algorithm.
        /// </returns>
        internal static Platform.HashAlgorithm CreateHashAlgorithm(HashAlgorithm algorithm)
        {
            string algorithmName = HashAlgorithmProviderFactory.GetHashAlgorithmName(algorithm);

            return(Platform.HashAlgorithm.Create(algorithmName));
        }