protected virtual void Dispose(bool disposing) { // we always want to clear the input buffer if (disposing) { if (_inputBuffer != null) { CryptographicOperations.ZeroMemory(_inputBuffer); _inputBuffer = null; } Reset(); } }
private static bool TryEncrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.Crypto.RsaPadding rsaPadding, RsaPaddingProcessor rsaPaddingProcessor, out int bytesWritten) { int rsaSize = Interop.Crypto.RsaSize(key); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } int returnValue; if (rsaPaddingProcessor != null) { Debug.Assert(rsaPadding == Interop.Crypto.RsaPadding.NoPadding); byte[] rented = ArrayPool <byte> .Shared.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { rsaPaddingProcessor.PadOaep(data, tmp); returnValue = Interop.Crypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding); } finally { CryptographicOperations.ZeroMemory(tmp); ArrayPool <byte> .Shared.Return(rented); } } else { Debug.Assert(rsaPadding != Interop.Crypto.RsaPadding.NoPadding); returnValue = Interop.Crypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding); } CheckReturn(returnValue); bytesWritten = returnValue; Debug.Assert(returnValue == rsaSize); return(true); }
private void DecryptCore( ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> ciphertext, ReadOnlySpan <byte> tag, Span <byte> plaintext, ReadOnlySpan <byte> associatedData) { Interop.Crypto.EvpCipherSetKeyAndIV( _ctxHandle, ReadOnlySpan <byte> .Empty, nonce, Interop.Crypto.EvpCipherDirection.Decrypt); if (!associatedData.IsEmpty) { Interop.Crypto.CipherUpdateAAD(_ctxHandle, associatedData); } if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext, out int plaintextBytesWritten, ciphertext)) { CryptographicOperations.ZeroMemory(plaintext); throw new CryptographicException(); } if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext.Slice(plaintextBytesWritten), out int bytesWritten, tag)) { CryptographicOperations.ZeroMemory(plaintext); throw new CryptographicException(); } plaintextBytesWritten += bytesWritten; if (!Interop.Crypto.EvpCipherFinalEx( _ctxHandle, plaintext.Slice(plaintextBytesWritten), out bytesWritten)) { CryptographicOperations.ZeroMemory(plaintext); throw new CryptographicException(SR.Cryptography_AuthTagMismatch); } plaintextBytesWritten += bytesWritten; if (plaintextBytesWritten != plaintext.Length) { Debug.Fail($"ChaCha20Poly1305 decrypt wrote {plaintextBytesWritten} of {plaintext.Length} bytes."); throw new CryptographicException(); } }
internal static unsafe Pkcs8Response ImportEncryptedPkcs8PrivateKey( ReadOnlySpan <byte> passwordBytes, ReadOnlySpan <byte> source, out int bytesRead) { fixed(byte *ptr = &MemoryMarshal.GetReference(source)) { using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length)) { // Since there's no bytes-based-password PKCS8 import in CNG, just do the decryption // here and call the unencrypted PKCS8 import. ArraySegment <byte> decrypted = KeyFormatHelper.DecryptPkcs8( passwordBytes, manager.Memory, out bytesRead); Span <byte> decryptedSpan = decrypted; try { return(ImportPkcs8(decryptedSpan)); } catch (CryptographicException e) { AsnWriter?pkcs8ZeroPublicKey = RewritePkcs8ECPrivateKeyWithZeroPublicKey(decryptedSpan); if (pkcs8ZeroPublicKey == null) { throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); } try { return(ImportPkcs8(pkcs8ZeroPublicKey.EncodeAsSpan())); } catch (CryptographicException) { throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); } } finally { CryptographicOperations.ZeroMemory(decryptedSpan); CryptoPool.Return(decrypted.Array !); } } } }
private static bool TryEncrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.AndroidCrypto.RsaPadding rsaPadding, HashAlgorithmName?oaepHashAlgorithmName, out int bytesWritten) { int rsaSize = Interop.AndroidCrypto.RsaSize(key); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } int returnValue; if (oaepHashAlgorithmName != null) { Debug.Assert(rsaPadding == Interop.AndroidCrypto.RsaPadding.NoPadding); byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { RsaPaddingProcessor.PadOaep(oaepHashAlgorithmName.Value, data, tmp); returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding); } finally { CryptographicOperations.ZeroMemory(tmp); CryptoPool.Return(rented, clearSize: 0); } } else { Debug.Assert(rsaPadding != Interop.AndroidCrypto.RsaPadding.NoPadding); returnValue = Interop.AndroidCrypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding); } CheckReturn(returnValue); bytesWritten = returnValue; Debug.Assert(returnValue == rsaSize, $"{returnValue} != {rsaSize}"); return(true); }
internal static void Return(byte[] array, int clearSize = ClearAll) { Debug.Assert(clearSize <= array.Length); bool clearWholeArray = clearSize < 0; if (!clearWholeArray && clearSize != 0) { #if NETCOREAPP || NETSTANDARD2_1 CryptographicOperations.ZeroMemory(array.AsSpan(0, clearSize)); #else Array.Clear(array, 0, clearSize); #endif } ArrayPool <byte> .Shared.Return(array, clearWholeArray); }
private unsafe AsnWriter WritePkcs8() { DSAParameters dsaParameters = ExportParameters(true); fixed(byte *privPin = dsaParameters.X) { try { return(DSAKeyFormatHelper.WritePkcs8(dsaParameters)); } finally { CryptographicOperations.ZeroMemory(dsaParameters.X); } } }
/// <summary> /// Exports the current key in the PKCS#1 RSAPrivateKey format, PEM encoded. /// </summary> /// <returns>A string containing the PEM-encoded PKCS#1 RSAPrivateKey.</returns> /// <exception cref="CryptographicException"> /// The key could not be exported. /// </exception> /// <remarks> /// <p> /// A PEM-encoded PKCS#1 RSAPrivateKey will begin with <c>-----BEGIN RSA PRIVATE KEY-----</c> /// and end with <c>-----END RSA PRIVATE KEY-----</c>, with the base64 encoded DER /// contents of the key between the PEM boundaries. /// </p> /// <p> /// The PEM is encoded according to the IETF RFC 7468 "strict" /// encoding rules. /// </p> /// </remarks> public unsafe string ExportRSAPrivateKeyPem() { byte[] exported = ExportRSAPrivateKey(); // Fixed to prevent GC moves. fixed(byte *pExported = exported) { try { return(PemKeyHelpers.CreatePemFromData(PemLabels.RsaPrivateKey, exported)); } finally { CryptographicOperations.ZeroMemory(exported); } } }
private static bool TryExportDataKeyParameters( SecKeyPair keys, bool includePrivateParameters, ref ECParameters ecParameters) { if (includePrivateParameters && keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); } bool gotKeyBlob = Interop.AppleCrypto.TrySecKeyCopyExternalRepresentation( includePrivateParameters ? keys.PrivateKey ! : keys.PublicKey, out byte[] keyBlob); if (!gotKeyBlob) { return(false); } try { AsymmetricAlgorithmHelpers.DecodeFromUncompressedAnsiX963Key( keyBlob, includePrivateParameters, out ecParameters); switch (GetKeySize(keys)) { case 256: ecParameters.Curve = ECCurve.NamedCurves.nistP256; break; case 384: ecParameters.Curve = ECCurve.NamedCurves.nistP384; break; case 521: ecParameters.Curve = ECCurve.NamedCurves.nistP521; break; default: Debug.Fail("Unsupported curve"); throw new CryptographicException(); } return(true); } finally { CryptographicOperations.ZeroMemory(keyBlob); } }
/// <summary> /// Imports the public/private keypair from an ECPrivateKey structure, /// replacing the keys for this object. /// </summary> /// <param name="source">The bytes of an ECPrivateKey structure in the ASN.1-BER encoding.</param> /// <param name="bytesRead"> /// When this method returns, contains a value that indicates the number /// of bytes read from <paramref name="source" />. This parameter is treated as uninitialized. /// </param> /// <exception cref="NotSupportedException"> /// A derived class has not provided an implementation for <see cref="ImportParameters" />. /// </exception> /// <exception cref="CryptographicException"> /// <p> /// The contents of <paramref name="source" /> do not represent an /// ASN.1-BER-encoded PKCS#8 ECPrivateKey structure. /// </p> /// <p>-or-</p> /// <p>The key import failed.</p> /// </exception> /// <remarks> /// This method only supports the binary (BER/CER/DER) encoding of ECPrivateKey. /// If the value is Base64-encoded, the caller must Base64-decode the contents before calling this method. /// If the value is PEM-encoded, <see cref="ImportFromPem" /> should be used. /// </remarks> public virtual unsafe void ImportECPrivateKey(ReadOnlySpan <byte> source, out int bytesRead) { ECParameters ecParameters = EccKeyFormatHelper.FromECPrivateKey(source, out int localRead); fixed(byte *privPin = ecParameters.D) { try { ImportParameters(ecParameters); bytesRead = localRead; } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
/// <summary>Exports the current key in the ECPrivateKey format.</summary> /// <returns>A byte array containing the ECPrivateKey representation of this key.</returns> /// <exception cref="CryptographicException">The key could not be exported.</exception> public virtual unsafe byte[] ExportECPrivateKey() { ECParameters ecParameters = ExportParameters(true); fixed(byte *privPin = ecParameters.D) { try { AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters); return(writer.Encode()); } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
/// <summary> /// Exports the current key in the PKCS#8 EncryptedPrivateKeyInfo format /// with a char-based password, PEM encoded. /// </summary> /// <param name="password"> /// The password to use when encrypting the key material. /// </param> /// <param name="pbeParameters"> /// The password-based encryption (PBE) parameters to use when encrypting the key material. /// </param> /// <returns>A string containing the PEM-encoded PKCS#8 EncryptedPrivateKeyInfo.</returns> /// <exception cref="NotImplementedException"> /// An implementation for <see cref="ExportEncryptedPkcs8PrivateKey(ReadOnlySpan{char}, PbeParameters)" /> or /// <see cref="TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan{char}, PbeParameters, Span{byte}, out int)" /> has not been provided. /// </exception> /// <exception cref="CryptographicException"> /// The key could not be exported. /// </exception> /// <remarks> /// <p> /// When <paramref name="pbeParameters" /> indicates an algorithm that /// uses PBKDF2 (Password-Based Key Derivation Function 2), the password /// is converted to bytes via the UTF-8 encoding. /// </p> /// <p> /// A PEM-encoded PKCS#8 EncryptedPrivateKeyInfo will begin with /// <c>-----BEGIN ENCRYPTED PRIVATE KEY-----</c> and end with /// <c>-----END ENCRYPTED PRIVATE KEY-----</c>, with the base64 encoded DER /// contents of the key between the PEM boundaries. /// </p> /// <p> /// The PEM is encoded according to the IETF RFC 7468 "strict" /// encoding rules. /// </p> /// </remarks> public unsafe string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan <char> password, PbeParameters pbeParameters) { byte[] exported = ExportEncryptedPkcs8PrivateKey(password, pbeParameters); // Fixed to prevent GC moves. fixed(byte *pExported = exported) { try { return(PemKeyHelpers.CreatePemFromData(PemLabels.EncryptedPkcs8PrivateKey, exported)); } finally { CryptographicOperations.ZeroMemory(exported); } } }
private bool TryDecrypt( SafeSecKeyRefHandle privateKey, ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { Debug.Assert(privateKey != null); if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1 || padding == RSAEncryptionPadding.OaepSHA1) { return(Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten)); } if (padding.Mode != RSAEncryptionPaddingMode.Oaep) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); int bytesRequired = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] rented = ArrayPool <byte> .Shared.Rent(bytesRequired); Span <byte> unpaddedData = Span <byte> .Empty; try { if (!Interop.AppleCrypto.TryRsaDecryptionPrimitive(privateKey, data, rented, out int paddedSize)) { Debug.Fail($"Raw decryption failed with KeySize={KeySize} and a buffer length {rented.Length}"); throw new CryptographicException(); } Debug.Assert(bytesRequired == paddedSize); unpaddedData = new Span <byte>(rented, 0, paddedSize); return(processor.DepadOaep(unpaddedData, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(unpaddedData); ArrayPool <byte> .Shared.Return(rented); } }
/// <summary> /// Attempts to export the current key in the ECPrivateKey format into a provided buffer. /// </summary> /// <param name="destination">The byte span to receive the ECPrivateKey data.</param> /// <param name="bytesWritten">When this method returns, contains a value /// that indicates the number of bytes written to <paramref name="destination" />. /// This parameter is treated as uninitialized. /// </param> /// <returns> /// <see langword="true" /> if <paramref name="destination" /> is big enough /// to receive the output; otherwise, <see langword="false" />. /// </returns> /// <exception cref="CryptographicException"> /// The key could not be exported. /// </exception> /// <exception cref="NotSupportedException"> /// A derived class has not provided an implementation for <see cref="ExportParameters" />. /// </exception> public virtual unsafe bool TryExportECPrivateKey(Span <byte> destination, out int bytesWritten) { ECParameters ecParameters = ExportParameters(true); fixed(byte *privPin = ecParameters.D) { try { AsnWriter writer = EccKeyFormatHelper.WriteECPrivateKey(ecParameters); return(writer.TryEncode(destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } SecKeyPair keys = GetKeys(); if (keys.PrivateKey == null) { throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); } if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1) { return(Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding)); } int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] rented = ArrayPool <byte> .Shared.Rent(maxOutputSize); Span <byte> contentsSpan = Span <byte> .Empty; try { if (!TryDecrypt(keys.PrivateKey, data, rented, padding, out int bytesWritten)) { Debug.Fail($"TryDecrypt returned false with a modulus-sized destination"); throw new CryptographicException(); } contentsSpan = new Span <byte>(rented, 0, bytesWritten); return(contentsSpan.ToArray()); } finally { CryptographicOperations.ZeroMemory(contentsSpan); ArrayPool <byte> .Shared.Return(rented); } }
private void DecryptInternal( ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> ciphertext, ReadOnlySpan <byte> tag, Span <byte> plaintext, ReadOnlySpan <byte> associatedData) { Interop.Crypto.EvpCipherSetKeyAndIV( _ctxHandle, ReadOnlySpan <byte> .Empty, nonce, Interop.Crypto.EvpCipherDirection.Decrypt); if (associatedData.Length != 0) { if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, Span <byte> .Empty, out _, associatedData)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } } if (!Interop.Crypto.EvpCipherUpdate(_ctxHandle, plaintext, out int plaintextBytesWritten, ciphertext)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } Interop.Crypto.EvpCipherSetGcmTag(_ctxHandle, tag); if (!Interop.Crypto.EvpCipherFinalEx( _ctxHandle, plaintext.Slice(plaintextBytesWritten), out int bytesWritten)) { CryptographicOperations.ZeroMemory(plaintext); throw new CryptographicException(SR.Cryptography_AuthTagMismatch); } plaintextBytesWritten += bytesWritten; if (plaintextBytesWritten != plaintext.Length) { Debug.Fail($"GCM decrypt wrote {plaintextBytesWritten} of {plaintext.Length} bytes."); throw new CryptographicException(); } }
public override DSAParameters ExportParameters(bool includePrivateParameters) { // Apple requires all private keys to be exported encrypted, but since we're trying to export // as parsed structures we will need to decrypt it for the user. const string ExportPassword = "******"; SecKeyPair keys = GetKeys(); if (keys.PublicKey == null || (includePrivateParameters && keys.PrivateKey == null)) { throw new CryptographicException(SR.Cryptography_OpenInvalidHandle); } byte[] keyBlob = Interop.AppleCrypto.SecKeyExport( includePrivateParameters ? keys.PrivateKey : keys.PublicKey, exportPrivate: includePrivateParameters, password: ExportPassword); try { if (!includePrivateParameters) { DSAKeyFormatHelper.ReadSubjectPublicKeyInfo( keyBlob, out int localRead, out DSAParameters key); Debug.Assert(localRead == keyBlob.Length); return(key); } else { DSAKeyFormatHelper.ReadEncryptedPkcs8( keyBlob, ExportPassword, out int localRead, out DSAParameters key); Debug.Assert(localRead == keyBlob.Length); return(key); } } finally { CryptographicOperations.ZeroMemory(keyBlob); } }
/// <summary> /// Computes the hash value of the specified data and signs it using the specified signature format. /// </summary> /// <param name="data">The data to sign.</param> /// <param name="hashAlgorithm">The hash algorithm to use to create the hash value.</param> /// <param name="signatureFormat">The encoding format to use for the signature.</param> /// <returns> /// The ECDSA signature for the specified data. /// </returns> /// <exception cref="CryptographicException"> /// An error occurred in the hashing or signing operation. /// </exception> protected virtual byte[] SignDataCore( ReadOnlySpan <byte> data, HashAlgorithmName hashAlgorithm, DSASignatureFormat signatureFormat) { Span <byte> signature = stackalloc byte[SignatureStackBufSize]; int maxSignatureSize = GetMaxSignatureSize(signatureFormat); byte[]? rented = null; bool returnArray = false; int bytesWritten = 0; if (maxSignatureSize > signature.Length) { // Use the shared pool because the buffer is passed out. rented = ArrayPool <byte> .Shared.Rent(maxSignatureSize); signature = rented; } try { if (!TrySignDataCore(data, signature, hashAlgorithm, signatureFormat, out bytesWritten)) { Debug.Fail($"GetMaxSignatureSize returned insufficient size for format {signatureFormat}"); throw new CryptographicException(); } byte[] ret = signature.Slice(0, bytesWritten).ToArray(); returnArray = true; return(ret); } finally { if (rented != null) { CryptographicOperations.ZeroMemory(rented.AsSpan(0, bytesWritten)); if (returnArray) { ArrayPool <byte> .Shared.Return(rented); } } } }
public override unsafe bool TryExportSubjectPublicKeyInfo(Span <byte> destination, out int bytesWritten) { // The PKCS1 RSAPublicKey format is just the modulus (KeySize bits) and Exponent (usually 3 bytes), // with each field having up to 7 bytes of overhead and then up to 6 extra bytes of overhead for the // SEQUENCE tag. // // So KeySize / 4 is ideally enough to start. int rentSize = KeySize / 4; while (true) { byte[] rented = ArrayPool <byte> .Shared.Rent(rentSize); rentSize = rented.Length; int pkcs1Size = 0; fixed(byte *rentPtr = rented) { try { if (!TryExportRSAPublicKey(rented, out pkcs1Size)) { rentSize = checked (rentSize * 2); continue; } using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER)) { writer.PushSequence(); WriteAlgorithmIdentifier(writer); writer.WriteBitString(rented.AsSpan(0, pkcs1Size)); writer.PopSequence(); return(writer.TryEncode(destination, out bytesWritten)); } } finally { CryptographicOperations.ZeroMemory(rented.AsSpan(0, pkcs1Size)); ArrayPool <byte> .Shared.Return(rented); } } } }
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor); SafeRsaHandle key = _key.Value; CheckInvalidKey(key); int rsaSize = Interop.Crypto.RsaSize(key); byte[] buf = null; Span <byte> destination = default; try { buf = ArrayPool <byte> .Shared.Rent(rsaSize); destination = new Span <byte>(buf, 0, rsaSize); if (!TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out int bytesWritten)) { Debug.Fail($"{nameof(TryDecrypt)} should not return false for RSA_size buffer"); throw new CryptographicException(); } return(destination.Slice(0, bytesWritten).ToArray()); } finally { CryptographicOperations.ZeroMemory(destination); ArrayPool <byte> .Shared.Return(buf); } }
public override unsafe bool TryExportPkcs8PrivateKey( Span <byte> destination, out int bytesWritten) { ECParameters ecParameters = ExportParameters(true); fixed(byte *privPtr = ecParameters.D) { try { using (AsnWriter writer = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters)) { return(writer.TryEncode(destination, out bytesWritten)); } } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
private static void Pbkdf2Core( ReadOnlySpan <char> password, ReadOnlySpan <byte> salt, Span <byte> destination, int iterations, HashAlgorithmName hashAlgorithm) { Debug.Assert(hashAlgorithm.Name is not null); Debug.Assert(iterations > 0); if (destination.IsEmpty) { return; } const int MaxPasswordStackSize = 256; byte[]? rentedPasswordBuffer = null; int maxEncodedSize = s_throwingUtf8Encoding.GetMaxByteCount(password.Length); Span <byte> passwordBuffer = maxEncodedSize > MaxPasswordStackSize ? (rentedPasswordBuffer = CryptoPool.Rent(maxEncodedSize)) : stackalloc byte[MaxPasswordStackSize]; int passwordBytesWritten = s_throwingUtf8Encoding.GetBytes(password, passwordBuffer); Span <byte> passwordBytes = passwordBuffer.Slice(0, passwordBytesWritten); try { Pbkdf2Implementation.Fill(passwordBytes, salt, iterations, hashAlgorithm, destination); } finally { CryptographicOperations.ZeroMemory(passwordBytes); } if (rentedPasswordBuffer is not null) { CryptoPool.Return(rentedPasswordBuffer, clearSize: 0); // manually cleared above. } }
private static unsafe byte[] ExportArray <T>( ReadOnlySpan <T> password, PbeParameters pbeParameters, TryExportPbe <T> exporter) { int bufSize = 4096; while (true) { Span <byte> writtenSpan = Span <byte> .Empty; byte[] buf = ArrayPool <byte> .Shared.Rent(bufSize); bufSize = buf.Length; fixed(byte *bufPtr = buf) { try { if (exporter(password, pbeParameters, buf, out int bytesWritten)) { writtenSpan = new Span <byte>(buf, 0, bytesWritten); return(writtenSpan.ToArray()); } } finally { if (writtenSpan.Length > 0) { CryptographicOperations.ZeroMemory(writtenSpan); } ArrayPool <byte> .Shared.Return(buf); } bufSize = checked (bufSize * 2); } } }
public override unsafe void ImportPkcs8PrivateKey( ReadOnlySpan <byte> source, out int bytesRead) { DSAKeyFormatHelper.ReadPkcs8( source, out int localRead, out DSAParameters key); fixed(byte *privPin = key.X) { try { ImportParameters(key); } finally { CryptographicOperations.ZeroMemory(key.X); } } bytesRead = localRead; }
private unsafe AsnWriter WritePkcs8PrivateKey() { // A PKCS1 RSAPrivateKey is the Modulus (KeySize bits), D (~KeySize bits) // P, Q, DP, DQ, InverseQ (all ~KeySize/2 bits) // Each field can have up to 7 bytes of overhead, and then another 9 bytes // of fixed overhead. // So it should fit in 5 * KeySizeInBytes, but Exponent is a wildcard. int rentSize = checked (5 * KeySize / 8); while (true) { byte[] rented = ArrayPool <byte> .Shared.Rent(rentSize); rentSize = rented.Length; int pkcs1Size = 0; fixed(byte *rentPtr = rented) { try { if (!TryExportRSAPrivateKey(rented, out pkcs1Size)) { rentSize = checked (rentSize * 2); continue; } return(RSAKeyFormatHelper.WritePkcs8PrivateKey(rented.AsSpan(0, pkcs1Size))); } finally { CryptographicOperations.ZeroMemory(rented.AsSpan(0, pkcs1Size)); ArrayPool <byte> .Shared.Return(rented); } } } }
private static AsnWriter RewriteEncryptedPkcs8PrivateKey( AsymmetricAlgorithm key, ReadOnlySpan <char> password, PbeParameters pbeParameters) { Debug.Assert(pbeParameters != null); byte[] rented = ArrayPool <byte> .Shared.Rent(key.KeySize); int rentWritten = 0; try { while (!key.TryExportEncryptedPkcs8PrivateKey( password, s_platformParameters, rented, out rentWritten)) { int size = rented.Length; ArrayPool <byte> .Shared.Return(rented); rented = ArrayPool <byte> .Shared.Rent(checked (size * 2)); } return(KeyFormatHelper.ReencryptPkcs8( password, rented.AsMemory(0, rentWritten), password, pbeParameters)); } finally { CryptographicOperations.ZeroMemory(rented.AsSpan(0, rentWritten)); ArrayPool <byte> .Shared.Return(rented); } }
public override unsafe bool TryExportEncryptedPkcs8PrivateKey( ReadOnlySpan <char> password, PbeParameters pbeParameters, Span <byte> destination, out int bytesWritten) { if (pbeParameters == null) { throw new ArgumentNullException(nameof(pbeParameters)); } PasswordBasedEncryption.ValidatePbeParameters( pbeParameters, password, ReadOnlySpan <byte> .Empty); ECParameters ecParameters = ExportParameters(true); fixed(byte *privPtr = ecParameters.D) { try { AsnWriter pkcs8PrivateKey = EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters); AsnWriter writer = KeyFormatHelper.WriteEncryptedPkcs8( password, pkcs8PrivateKey, pbeParameters); return(writer.TryEncode(destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(ecParameters.D); } } }
/// <summary> /// Imports the public/private keypair from a PKCS#8 PrivateKeyInfo structure /// after decryption, replacing the keys for this object. /// </summary> /// <param name="source">The bytes of a PKCS#8 PrivateKeyInfo structure in the ASN.1-BER encoding.</param> /// <param name="bytesRead"> /// When this method returns, contains a value that indicates the number /// of bytes read from <paramref name="source" />. This parameter is treated as uninitialized. /// </param> /// <exception cref="NotSupportedException"> /// A derived class has not provided an implementation for <see cref="ImportParameters" />. /// </exception> /// <exception cref="CryptographicException"> /// <p> /// The contents of <paramref name="source" /> do not represent an ASN.1-BER-encoded /// PKCS#8 PrivateKeyInfo structure. /// </p> /// <p>-or-</p> /// <p> /// The contents of <paramref name="source" /> indicate the key is for an algorithm /// other than the algorithm represented by this instance. /// </p> /// <p>-or-</p> /// <p>The contents of <paramref name="source" /> represent the key in a format that is not supported.</p> /// <p>-or-</p> /// <p> /// The algorithm-specific key import failed. /// </p> /// </exception> /// <remarks> /// This method only supports the binary (BER/CER/DER) encoding of PrivateKeyInfo. /// If the value is Base64-encoded, the caller must Base64-decode the contents before calling this method. /// If the value is PEM-encoded, <see cref="ImportFromPem" /> should be used. /// </remarks> public override unsafe void ImportPkcs8PrivateKey( ReadOnlySpan <byte> source, out int bytesRead) { KeyFormatHelper.ReadPkcs8 <ECParameters>( s_validOids, source, EccKeyFormatHelper.FromECPrivateKey, out int localRead, out ECParameters key); fixed(byte *privPin = key.D) { try { ImportParameters(key); bytesRead = localRead; } finally { CryptographicOperations.ZeroMemory(key.D); } } }
public Rfc2898DeriveBytes(string password, int saltSize, int iterations, HashAlgorithmName hashAlgorithm) { if (saltSize < 0) { throw new ArgumentOutOfRangeException(nameof(saltSize), SR.ArgumentOutOfRange_NeedNonNegNum); } if (iterations <= 0) { throw new ArgumentOutOfRangeException(nameof(iterations), SR.ArgumentOutOfRange_NeedPosNum); } _salt = new byte[saltSize + sizeof(uint)]; RandomNumberGenerator.Fill(_salt.AsSpan(0, saltSize)); _iterations = (uint)iterations; byte[] passwordBytes = Encoding.UTF8.GetBytes(password); HashAlgorithm = hashAlgorithm; _hmac = OpenHmac(passwordBytes); CryptographicOperations.ZeroMemory(passwordBytes); // _blockSize is in bytes, HashSize is in bits. _blockSize = _hmac.HashSize >> 3; Initialize(); }
private static ECParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool includePrivateParameters) { // Apple requires all private keys to be exported encrypted, but since we're trying to export // as parsed structures we will need to decrypt it for the user. const string ExportPassword = "******"; byte[] keyBlob = Interop.AppleCrypto.SecKeyExport( includePrivateParameters ? keys.PrivateKey : keys.PublicKey, exportPrivate: includePrivateParameters, password: ExportPassword); try { if (!includePrivateParameters) { EccKeyFormatHelper.ReadSubjectPublicKeyInfo( keyBlob, out int localRead, out ECParameters key); return(key); } else { EccKeyFormatHelper.ReadEncryptedPkcs8( keyBlob, ExportPassword, out int localRead, out ECParameters key); return(key); } } finally { CryptographicOperations.ZeroMemory(keyBlob); } }