private bool TryExportPublicKey( Func <ReadOnlyMemory <byte>, ReadOnlyMemory <byte> >?transform, Span <byte> destination, out int bytesWritten) { // It's entirely possible that this line will cause the key to be generated in the first place. SafeEvpPKeyHandle key = GetKey(); ArraySegment <byte> spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key); try { ReadOnlyMemory <byte> data = spki; if (transform != null) { data = transform(data); } return(data.Span.TryCopyToDestination(destination, out bytesWritten)); } finally { CryptoPool.Return(spki); } }
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } ValidatePadding(padding); SafeEvpPKeyHandle key = GetKey(); int rsaSize = Interop.Crypto.EvpPKeySize(key); Span <byte> destination = default; byte[] buf = CryptoPool.Rent(rsaSize); try { destination = new Span <byte>(buf, 0, rsaSize); int bytesWritten = Decrypt(key, data, destination, padding); return(destination.Slice(0, bytesWritten).ToArray()); } finally { CryptographicOperations.ZeroMemory(destination); CryptoPool.Return(buf, clearSize: 0); } }
private static unsafe byte[] ExportArray <T>( ReadOnlySpan <T> password, PbeParameters pbeParameters, TryExportPbe <T> exporter) { int bufSize = 4096; while (true) { byte[] buf = CryptoPool.Rent(bufSize); int bytesWritten = 0; bufSize = buf.Length; fixed(byte *bufPtr = buf) { try { if (exporter(password, pbeParameters, buf, out bytesWritten)) { Span <byte> writtenSpan = new Span <byte>(buf, 0, bytesWritten); return(writtenSpan.ToArray()); } } finally { CryptoPool.Return(buf, bytesWritten); } bufSize = checked (bufSize * 2); } } }
private static unsafe byte[] ExportArray(TryExport exporter) { int bufSize = 4096; while (true) { byte[] buf = CryptoPool.Rent(bufSize); int bytesWritten = 0; bufSize = buf.Length; fixed(byte *bufPtr = buf) { try { if (exporter(buf, out bytesWritten)) { Span <byte> writtenSpan = new Span <byte>(buf, 0, bytesWritten); return(writtenSpan.ToArray()); } } finally { CryptoPool.Return(buf, bytesWritten); } bufSize = checked (bufSize * 2); } } }
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { ArgumentNullException.ThrowIfNull(data); ArgumentNullException.ThrowIfNull(padding); Interop.AndroidCrypto.RsaPadding rsaPadding = GetInteropPadding(padding); SafeRsaHandle key = GetKey(); int rsaSize = Interop.AndroidCrypto.RsaSize(key); Span <byte> destination = default; byte[] buf = CryptoPool.Rent(rsaSize); try { destination = new Span <byte>(buf, 0, rsaSize); if (!TryDecrypt(key, data, destination, rsaPadding, 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); CryptoPool.Return(buf, clearSize: 0); } }
private static SafeSecKeyRefHandle ImportLegacyPrivateKey(RSAParameters parameters) { Debug.Assert(parameters.D != null); AsnWriter keyWriter = RSAKeyFormatHelper.WritePkcs1PrivateKey(parameters); byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); if (!keyWriter.TryEncode(rented, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } // Explicitly clear the inner buffer keyWriter.Reset(); try { return(Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), true)); } finally { CryptoPool.Return(rented, written); } }
private static AsnWriter RewriteEncryptedPkcs8PrivateKey( AsymmetricAlgorithm key, ReadOnlySpan <char> password, PbeParameters pbeParameters) { Debug.Assert(pbeParameters != null); byte[] rented = CryptoPool.Rent(key.KeySize); int rentWritten = 0; try { while (!key.TryExportEncryptedPkcs8PrivateKey( password, s_platformParameters, rented, out rentWritten)) { int size = rented.Length; byte[] current = rented; rented = CryptoPool.Rent(checked (size * 2)); CryptoPool.Return(current, rentWritten); } return(KeyFormatHelper.ReencryptPkcs8( password, rented.AsMemory(0, rentWritten), password, pbeParameters)); } finally { CryptoPool.Return(rented, rentWritten); } }
public unsafe int Transform(ReadOnlySpan <byte> input, Span <byte> output) { #if DEBUG if (_isFinalized) { Debug.Fail("Cipher was reused without being reset."); throw new CryptographicException(); } #endif // OpenSSL 1.1 does not allow partial overlap. if (input.Overlaps(output, out int overlapOffset) && overlapOffset != 0) { byte[] tmp = CryptoPool.Rent(input.Length); Span <byte> tmpSpan = tmp; int written = 0; try { written = CipherUpdate(input, tmpSpan); tmpSpan.Slice(0, written).CopyTo(output); return(written); } finally { CryptoPool.Return(tmp, written); } } return(CipherUpdate(input, output)); }
public override byte[] CreateSignature(byte[] rgbHash) { if (rgbHash == null) { throw new ArgumentNullException(nameof(rgbHash)); } SafeDsaHandle key = GetKey(); int signatureSize = Interop.Crypto.DsaEncodedSignatureSize(key); byte[] signature = CryptoPool.Rent(signatureSize); try { bool success = Interop.Crypto.DsaSign(key, rgbHash, new Span <byte>(signature, 0, signatureSize), out signatureSize); if (!success) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } Debug.Assert( signatureSize <= signature.Length, "DSA_sign reported an unexpected signature size", "DSA_sign reported signatureSize was {0}, when <= {1} was expected", signatureSize, signature.Length); int signatureFieldSize = Interop.Crypto.DsaSignatureFieldSize(key) * BitsPerByte; return(AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureSize, signatureFieldSize)); } finally { CryptoPool.Return(signature, signatureSize); } }
protected override unsafe byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { if (SymmetricPadding.DepaddingRequired(PaddingMode)) { byte[] rented = CryptoPool.Rent(inputCount + InputBlockSize); int written = 0; fixed(byte *pRented = rented) { try { written = UncheckedTransformFinalBlock(inputBuffer.AsSpan(inputOffset, inputCount), rented); return(rented.AsSpan(0, written).ToArray()); } finally { CryptoPool.Return(rented, clearSize: written); } } } else { byte[] buffer = GC.AllocateUninitializedArray <byte>(inputCount); int written = UncheckedTransformFinalBlock(inputBuffer.AsSpan(inputOffset, inputCount), buffer); Debug.Assert(written == buffer.Length); return(buffer); } }
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 = CryptoPool.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(new ReadOnlySpan <byte>(rented, 0, pkcs1Size))); } finally { CryptoPool.Return(rented, pkcs1Size); } } } }
public override bool TrySignHash(ReadOnlySpan <byte> hash, Span <byte> destination, out int bytesWritten) { ThrowIfDisposed(); SafeEcKeyHandle key = _key.Value; byte[] converted; int signatureLength = Interop.Crypto.EcDsaSize(key); byte[] signature = CryptoPool.Rent(signatureLength); try { if (!Interop.Crypto.EcDsaSign(hash, new Span <byte>(signature, 0, signatureLength), ref signatureLength, key)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } converted = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(signature, 0, signatureLength, KeySize); } finally { CryptoPool.Return(signature, signatureLength); } if (converted.Length <= destination.Length) { new ReadOnlySpan <byte>(converted).CopyTo(destination); bytesWritten = converted.Length; return(true); } else { bytesWritten = 0; return(false); } }
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 = CryptoPool.Rent(rentSize); rentSize = rented.Length; int pkcs1Size = 0; fixed(byte *rentPtr = rented) { try { if (!TryExportRSAPublicKey(rented, out pkcs1Size)) { rentSize = checked (rentSize * 2); continue; } AsnWriter writer = RSAKeyFormatHelper.WriteSubjectPublicKeyInfo(rented.AsSpan(0, pkcs1Size)); return(writer.TryEncode(destination, out bytesWritten)); } finally { CryptoPool.Return(rented, pkcs1Size); } } } }
public virtual bool VerifyData(ReadOnlySpan <byte> data, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } for (int i = 256; ; i = checked (i * 2)) { int hashLength = 0; byte[] hash = CryptoPool.Rent(i); try { if (TryHashData(data, hash, hashAlgorithm, out hashLength)) { return(VerifyHash(new ReadOnlySpan <byte>(hash, 0, hashLength), signature, hashAlgorithm, padding)); } } finally { CryptoPool.Return(hash, hashLength); } } }
private void ReturnToCryptoPool(byte[] array, int clearSize) { if (array != null) { CryptoPool.Return(array, clearSize); } }
public override bool TryDecrypt( ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { ArgumentNullException.ThrowIfNull(padding); ValidatePadding(padding); SafeEvpPKeyHandle key = GetKey(); int keySizeBytes = Interop.Crypto.EvpPKeySize(key); // OpenSSL requires that the decryption buffer be at least as large as EVP_PKEY_size. // So if the destination is too small, use a temporary buffer so we can match // Windows behavior of succeeding so long as the buffer can hold the final output. if (destination.Length < keySizeBytes) { // RSA up through 4096 bits use a stackalloc Span <byte> tmp = stackalloc byte[512]; byte[]? rent = null; if (keySizeBytes > tmp.Length) { rent = CryptoPool.Rent(keySizeBytes); tmp = rent; } int written = Decrypt(key, data, tmp, padding); bool ret; if (destination.Length < written) { bytesWritten = 0; ret = false; } else { tmp.Slice(0, written).CopyTo(destination); bytesWritten = written; ret = true; } // Whether a stackalloc or a rented array, clear our copy of // the decrypted content. CryptographicOperations.ZeroMemory(tmp.Slice(0, written)); if (rent != null) { // Already cleared. CryptoPool.Return(rent, clearSize: 0); } return(ret); } bytesWritten = Decrypt(key, data, destination, padding); return(true); }
private static AsnWriter RewriteEncryptedPkcs8PrivateKey( AsymmetricAlgorithm key, ReadOnlySpan <byte> passwordBytes, PbeParameters pbeParameters) { Debug.Assert(pbeParameters != null); // For RSA: // * 512-bit key needs ~400 bytes // * 16384-bit key needs ~10k bytes. // * KeySize (bits) should avoid re-rent. // // For DSA: // * 512-bit key needs ~300 bytes. // * 1024-bit key needs ~400 bytes. // * 2048-bit key needs ~700 bytes. // * KeySize (bits) should avoid re-rent. // // For ECC: // * secp256r1 needs ~200 bytes (named) or ~450 (explicit) // * secp384r1 needs ~250 bytes (named) or ~600 (explicit) // * secp521r1 needs ~300 bytes (named) or ~730 (explicit) // * KeySize (bits) should avoid re-rent for named, and probably // gets one re-rent for explicit. byte[] rented = CryptoPool.Rent(key.KeySize); int rentWritten = 0; // If we use 6 bits from each byte, that's 22 * 6 = 132 Span <char> randomString = stackalloc char[22]; try { FillRandomAsciiString(randomString); while (!key.TryExportEncryptedPkcs8PrivateKey( randomString, s_platformParameters, rented, out rentWritten)) { int size = rented.Length; byte[] current = rented; rented = CryptoPool.Rent(checked (size * 2)); CryptoPool.Return(current, rentWritten); } return(KeyFormatHelper.ReencryptPkcs8( randomString, rented.AsMemory(0, rentWritten), passwordBytes, pbeParameters)); } finally { randomString.Clear(); CryptoPool.Return(rented, rentWritten); } }
public override bool VerifyHash(ReadOnlySpan <byte> hash, ReadOnlySpan <byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (string.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1) { int algorithmNid = GetAlgorithmNid(hashAlgorithm); SafeRsaHandle rsa = _key.Value; return(Interop.Crypto.RsaVerify(algorithmNid, hash, signature, rsa)); } else if (padding == RSASignaturePadding.Pss) { RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); SafeRsaHandle rsa = _key.Value; int requiredBytes = Interop.Crypto.RsaSize(rsa); if (signature.Length != requiredBytes) { return(false); } if (hash.Length != processor.HashLength) { return(false); } byte[] rented = CryptoPool.Rent(requiredBytes); Span <byte> unwrapped = new Span <byte>(rented, 0, requiredBytes); try { int ret = Interop.Crypto.RsaVerificationPrimitive(signature, unwrapped, rsa); CheckReturn(ret); Debug.Assert( ret == requiredBytes, $"RSA_private_encrypt returned {ret} when {requiredBytes} was expected"); return(processor.VerifyPss(hash, unwrapped, KeySize)); } finally { CryptoPool.Return(rented, requiredBytes); } } throw PaddingModeNotSupported(); }
private static SafeSecKeyRefHandle ImportKey(DSAParameters parameters) { AsnWriter keyWriter; bool hasPrivateKey; if (parameters.X != null) { // DSAPrivateKey ::= SEQUENCE( // version INTEGER, // p INTEGER, // q INTEGER, // g INTEGER, // y INTEGER, // x INTEGER, // ) keyWriter = new AsnWriter(AsnEncodingRules.DER); using (keyWriter.PushSequence()) { keyWriter.WriteInteger(0); keyWriter.WriteKeyParameterInteger(parameters.P); keyWriter.WriteKeyParameterInteger(parameters.Q); keyWriter.WriteKeyParameterInteger(parameters.G); keyWriter.WriteKeyParameterInteger(parameters.Y); keyWriter.WriteKeyParameterInteger(parameters.X); } hasPrivateKey = true; } else { keyWriter = DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); hasPrivateKey = false; } byte[] rented = CryptoPool.Rent(keyWriter.GetEncodedLength()); if (!keyWriter.TryEncode(rented, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new InvalidOperationException(); } // Explicitly clear the inner buffer keyWriter.Reset(); try { return(Interop.AppleCrypto.ImportEphemeralKey(rented.AsSpan(0, written), hasPrivateKey)); } finally { CryptoPool.Return(rented, written); } }
public override bool TryEncrypt(ReadOnlySpan <byte> data, Span <byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { ArgumentNullException.ThrowIfNull(padding); ThrowIfDisposed(); int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } if (data.Length == 0) { if (padding.Mode != RSAEncryptionPaddingMode.Pkcs1 && padding.Mode != RSAEncryptionPaddingMode.Oaep) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } byte[] rented = CryptoPool.Rent(rsaSize); Span <byte> tmp = new Span <byte>(rented, 0, rsaSize); try { if (padding.Mode == RSAEncryptionPaddingMode.Oaep) { RsaPaddingProcessor.PadOaep(padding.OaepHashAlgorithm, data, tmp); } else { Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Pkcs1); RsaPaddingProcessor.PadPkcs1Encryption(data, tmp); } return(Interop.AppleCrypto.TryRsaEncryptionPrimitive( GetKeys().PublicKey, tmp, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(tmp); CryptoPool.Return(rented, clearSize: 0); } } return(Interop.AppleCrypto.TryRsaEncrypt( GetKeys().PublicKey, data, destination, padding, out bytesWritten)); }
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)) { try { // 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)); } catch (CryptographicException) { throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); } } finally { CryptoPool.Return(decrypted); } } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); } } } }
public int TransformFinal(ReadOnlySpan <byte> input, Span <byte> output) { #if DEBUG if (_isFinalized) { Debug.Fail("Cipher was reused without being reset."); throw new CryptographicException(); } _isFinalized = true; #endif // We just use CCCryptorUpdate instead of CCCryptorFinal. From the // Apple documentation: // In the following cases, the CCCryptorFinal() is superfluous as // it will not yield any data nor return an error: // 1. Encrypting or decrypting with a block cipher with padding // disabled, when the total amount of data provided to // CCCryptorUpdate() is an integral multiple of the block size. // 2. Encrypting or decrypting with a stream cipher. // For case 1, we do all of our padding manually and the cipher is opened with // PAL_PaddingMode.None. So that condition is met. For the second part, we always // submit data as a multiple of the block size, and is asserted below. So this condition // is met. Debug.Assert((input.Length % PaddingSizeInBytes) == 0); Debug.Assert(input.Length <= output.Length); int written = 0; if (input.Overlaps(output, out int offset) && offset != 0) { byte[] rented = CryptoPool.Rent(output.Length); try { written = CipherUpdate(input, rented); rented.AsSpan(0, written).CopyTo(output); } finally { CryptoPool.Return(rented, clearSize: written); } } else { written = CipherUpdate(input, output); } return(written); }
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.Mode != RSAEncryptionPaddingMode.Oaep) { throw new CryptographicException(SR.Cryptography_InvalidPaddingMode); } int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (data.Length != modulusSizeInBytes) { throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1 || padding == RSAEncryptionPadding.OaepSHA1) { return(Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten)); } Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Oaep); RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm); byte[] rented = CryptoPool.Rent(modulusSizeInBytes); 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(modulusSizeInBytes == paddedSize); unpaddedData = new Span <byte>(rented, 0, paddedSize); return(processor.DepadOaep(unpaddedData, destination, out bytesWritten)); } finally { CryptographicOperations.ZeroMemory(unpaddedData); CryptoPool.Return(rented, clearSize: 0); } }
internal static unsafe Pkcs8Response ImportEncryptedPkcs8PrivateKey( ReadOnlySpan <char> password, ReadOnlySpan <byte> source, out int bytesRead) { fixed(byte *ptr = &MemoryMarshal.GetReference(source)) { using (MemoryManager <byte> manager = new PointerMemoryManager <byte>(ptr, source.Length)) { AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER); int len = reader.ReadEncodedValue().Length; source = source.Slice(0, len); try { bytesRead = len; return(ImportPkcs8(source, password)); } catch (CryptographicException) { } ArraySegment <byte> decrypted = KeyFormatHelper.DecryptPkcs8( password, manager.Memory.Slice(0, len), out int innerRead); Span <byte> decryptedSpan = decrypted; try { if (innerRead != len) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } bytesRead = len; return(ImportPkcs8(decryptedSpan)); } catch (CryptographicException e) { throw new CryptographicException(SR.Cryptography_Pkcs8_EncryptedReadFailed, e); } finally { CryptographicOperations.ZeroMemory(decryptedSpan); CryptoPool.Return(decrypted.Array, clearSize: 0); } } } }
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); } int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); if (data.Length != modulusSizeInBytes) { throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize); } if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1) { return(Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding)); } int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize); byte[] rented = CryptoPool.Rent(maxOutputSize); int bytesWritten = 0; try { if (!TryDecrypt(keys.PrivateKey, data, rented, padding, out bytesWritten)) { Debug.Fail($"TryDecrypt returned false with a modulus-sized destination"); throw new CryptographicException(); } Span <byte> contentsSpan = new Span <byte>(rented, 0, bytesWritten); return(contentsSpan.ToArray()); } finally { CryptoPool.Return(rented, bytesWritten); } }
private static Pkcs8Response ImportPkcs8(AsnWriter pkcs8Writer) { byte[] tmp = CryptoPool.Rent(pkcs8Writer.GetEncodedLength()); if (!pkcs8Writer.TryEncode(tmp, out int written)) { Debug.Fail("TryEncode failed with a pre-allocated buffer"); throw new CryptographicException(); } Pkcs8Response ret = ImportPkcs8(tmp.AsSpan(0, written)); CryptoPool.Return(tmp, written); return(ret); }
private static bool TryEncrypt( SafeRsaHandle key, ReadOnlySpan <byte> data, Span <byte> destination, Interop.AndroidCrypto.RsaPadding rsaPadding, RsaPaddingProcessor?rsaPaddingProcessor, out int bytesWritten) { int rsaSize = Interop.AndroidCrypto.RsaSize(key); if (destination.Length < rsaSize) { bytesWritten = 0; return(false); } int returnValue; if (rsaPaddingProcessor != 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(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); }
private T ExportPublicKey <T>(Func <ReadOnlyMemory <byte>, T> exporter) { // It's entirely possible that this line will cause the key to be generated in the first place. SafeEvpPKeyHandle key = GetKey(); ArraySegment <byte> spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key); try { return(exporter(spki)); } finally { CryptoPool.Return(spki); } }
private T ExportPrivateKey <T>(ExportPrivateKeyFunc <T> exporter) { // It's entirely possible that this line will cause the key to be generated in the first place. SafeEvpPKeyHandle key = GetKey(); ArraySegment <byte> p8 = Interop.Crypto.RentEncodePkcs8PrivateKey(key); try { ReadOnlyMemory <byte> pkcs1 = VerifyPkcs8(p8); return(exporter(p8, pkcs1)); } finally { CryptoPool.Return(p8); } }
public int Transform(ReadOnlySpan <byte> input, Span <byte> output) { Debug.Assert(input.Length > 0); Debug.Assert((input.Length % PaddingSizeInBytes) == 0); int numBytesWritten = 0; // BCryptEncrypt and BCryptDecrypt can do in place encryption, but if the buffers overlap // the offset must be zero. In that case, we need to copy to a temporary location. if (input.Overlaps(output, out int offset) && offset != 0) { byte[] rented = CryptoPool.Rent(output.Length); try { numBytesWritten = BCryptTransform(input, rented); rented.AsSpan(0, numBytesWritten).CopyTo(output); } finally { CryptoPool.Return(rented, clearSize: numBytesWritten); } } else { numBytesWritten = BCryptTransform(input, output); } if (numBytesWritten != input.Length) { // CNG gives us no way to tell BCryptDecrypt() that we're decrypting the final block, nor is it performing any // padding /depadding for us. So there's no excuse for a provider to hold back output for "future calls." Though // this isn't technically our problem to detect, we might as well detect it now for easier diagnosis. throw new CryptographicException(SR.Cryptography_UnexpectedTransformTruncation); } return(numBytesWritten); int BCryptTransform(ReadOnlySpan <byte> input, Span <byte> output) { return(_encrypting ? Interop.BCrypt.BCryptEncrypt(_hKey, input, _currentIv, output) : Interop.BCrypt.BCryptDecrypt(_hKey, input, _currentIv, output)); } }