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); } }
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 = ArrayPool <byte> .Shared.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; ArrayPool <byte> .Shared.Return(rented); rented = ArrayPool <byte> .Shared.Rent(checked (size * 2)); } return(KeyFormatHelper.ReencryptPkcs8( randomString, rented.AsMemory(0, rentWritten), passwordBytes, pbeParameters)); } finally { randomString.Clear(); CryptographicOperations.ZeroMemory(rented.AsSpan(0, rentWritten)); ArrayPool <byte> .Shared.Return(rented); } }
internal static bool TryExportEncryptedPkcs8PrivateKey( AsymmetricAlgorithm key, ReadOnlySpan <byte> passwordBytes, PbeParameters pbeParameters, Span <byte> destination, out int bytesWritten) { if (passwordBytes.Length == 0) { // Switch to character-based, since that's the native input format. return(key.TryExportEncryptedPkcs8PrivateKey( ReadOnlySpan <char> .Empty, pbeParameters, destination, out bytesWritten)); } AsnWriter writer = RewriteEncryptedPkcs8PrivateKey(key, passwordBytes, pbeParameters); return(writer.TryEncode(destination, out bytesWritten)); }