public unsafe void SignHash() { using (var provider = NCryptOpenStorageProvider(KeyStorageProviders.MS_KEY_STORAGE_PROVIDER)) { using (var keyPair = NCryptCreatePersistedKey(provider, BCrypt.AlgorithmIdentifiers.BCRYPT_RSA_ALGORITHM)) { int keySize = GetMinimumKeySize(keyPair); NCryptSetProperty(keyPair, KeyStoragePropertyIdentifiers.NCRYPT_LENGTH_PROPERTY, keySize); NCryptFinalizeKey(keyPair).ThrowOnError(); byte[] hashData = SHA1.Create().ComputeHash(new byte[] { 0x1 }); var flags = NCryptSignHashFlags.BCRYPT_PAD_PKCS1; fixed(char *pAlgorithm = BCrypt.AlgorithmIdentifiers.BCRYPT_SHA1_ALGORITHM.ToCharArrayWithNullTerminator()) { var paddingInfo = new BCrypt.BCRYPT_PKCS1_PADDING_INFO() { pszAlgId = pAlgorithm, }; byte[] signature = NCryptSignHash(keyPair, &paddingInfo, hashData, flags).ToArray(); bool valid = NCryptVerifySignature(keyPair, &paddingInfo, hashData, signature, flags); Assert.True(valid); signature[0] = unchecked ((byte)(signature[0] + 1)); valid = NCryptVerifySignature(keyPair, &paddingInfo, hashData, signature, flags); Assert.False(valid); } } } }
/// <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(); } } } }