/// <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(); } }
/// <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(); } } } }
/// <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); } } } }
/// <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)); }