Skip to content

Commit

Permalink
Add PEM PKCS#8 and SPKI exports for AsymmetricAlgorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
vcsjones authored Nov 11, 2021
1 parent 8684c21 commit 2099752
Show file tree
Hide file tree
Showing 9 changed files with 701 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,106 @@

namespace Internal.Cryptography
{
internal static class PemKeyImportHelpers
internal static class PemKeyHelpers
{
public delegate bool TryExportKeyAction<T>(T arg, Span<byte> destination, out int bytesWritten);
public delegate bool TryExportEncryptedKeyAction<T>(
T arg,
ReadOnlySpan<char> password,
PbeParameters pbeParameters,
Span<byte> destination,
out int bytesWritten);

public static unsafe bool TryExportToEncryptedPem<T>(
T arg,
ReadOnlySpan<char> password,
PbeParameters pbeParameters,
TryExportEncryptedKeyAction<T> exporter,
Span<char> destination,
out int charsWritten)
{
int bufferSize = 4096;

while (true)
{
byte[] buffer = CryptoPool.Rent(bufferSize);
int bytesWritten = 0;
bufferSize = buffer.Length;

// Fixed to prevent GC moves.
fixed (byte* bufferPtr = buffer)
{
try
{
if (exporter(arg, password, pbeParameters, buffer, out bytesWritten))
{
Span<byte> writtenSpan = new Span<byte>(buffer, 0, bytesWritten);
return PemEncoding.TryWrite(PemLabels.EncryptedPkcs8PrivateKey, writtenSpan, destination, out charsWritten);
}
}
finally
{
CryptoPool.Return(buffer, bytesWritten);
}

bufferSize = checked(bufferSize * 2);
}
}
}

public static unsafe bool TryExportToPem<T>(
T arg,
string label,
TryExportKeyAction<T> exporter,
Span<char> destination,
out int charsWritten)
{
int bufferSize = 4096;

while (true)
{
byte[] buffer = CryptoPool.Rent(bufferSize);
int bytesWritten = 0;
bufferSize = buffer.Length;

// Fixed to prevent GC moves.
fixed (byte* bufferPtr = buffer)
{
try
{
if (exporter(arg, buffer, out bytesWritten))
{
Span<byte> writtenSpan = new Span<byte>(buffer, 0, bytesWritten);
return PemEncoding.TryWrite(label, writtenSpan, destination, out charsWritten);
}
}
finally
{
CryptoPool.Return(buffer, bytesWritten);
}

bufferSize = checked(bufferSize * 2);
}
}
}

internal static string CreatePemFromData(string label, ReadOnlyMemory<byte> data)
{
int pemSize = PemEncoding.GetEncodedSize(label.Length, data.Length);

return string.Create(pemSize, (label, data), static (destination, args) =>
{
(string label, ReadOnlyMemory<byte> data) = args;

if (!PemEncoding.TryWrite(label, data.Span, destination, out int charsWritten) ||
charsWritten != destination.Length)
{
Debug.Fail("Pre-allocated buffer was not the correct size.");
throw new CryptographicException();
}
});
}

public delegate void ImportKeyAction(ReadOnlySpan<byte> source, out int bytesRead);
public delegate ImportKeyAction? FindImportActionFunc(ReadOnlySpan<char> label);
public delegate void ImportEncryptedKeyAction<TPass>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@
Link="Internal\Cryptography\BasicSymmetricCipher.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\Helpers.cs"
Link="Internal\Cryptography\Helpers.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\PemKeyImportHelpers.cs"
Link="Common\Internal\Cryptography\PemKeyImportHelpers.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\PemKeyHelpers.cs"
Link="Common\Internal\Cryptography\PemKeyHelpers.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\ILiteSymmetricCipher.cs"
Link="Internal\Cryptography\ILiteSymmetricCipher.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\SymmetricPadding.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ public virtual unsafe bool TryExportECPrivateKey(Span<byte> destination, out int
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
PemKeyHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey))
{
return ImportPkcs8PrivateKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,7 @@ public int GetMaxSignatureSize(DSASignatureFormat signatureFormat)
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
PemKeyHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.Pkcs8PrivateKey))
{
return ImportPkcs8PrivateKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ public override unsafe void ImportEncryptedPkcs8PrivateKey(
/// </remarks>
public override void ImportFromPem(ReadOnlySpan<char> input)
{
PemKeyImportHelpers.ImportPem(input, label => {
PemKeyHelpers.ImportPem(input, label => {
if (label.SequenceEqual(PemLabels.RsaPrivateKey))
{
return ImportRSAPrivateKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,11 @@ public void Dispose() { }
protected virtual void Dispose(bool disposing) { }
public virtual byte[] ExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.Security.Cryptography.PbeParameters pbeParameters) { throw null; }
public virtual byte[] ExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.Security.Cryptography.PbeParameters pbeParameters) { throw null; }
public string ExportEncryptedPkcs8PrivateKeyPem(System.ReadOnlySpan<char> password, System.Security.Cryptography.PbeParameters pbeParameters) { throw null; }
public virtual byte[] ExportPkcs8PrivateKey() { throw null; }
public string ExportPkcs8PrivateKeyPem() { throw null; }
public virtual byte[] ExportSubjectPublicKeyInfo() { throw null; }
public string ExportSubjectPublicKeyInfoPem() { throw null; }
public virtual void FromXmlString(string xmlString) { }
public virtual void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
public virtual void ImportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> source, out int bytesRead) { throw null; }
Expand All @@ -76,8 +79,11 @@ public virtual void ImportFromPem(System.ReadOnlySpan<char> input) { }
public virtual string ToXmlString(bool includePrivateParameters) { throw null; }
public virtual bool TryExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<byte> passwordBytes, System.Security.Cryptography.PbeParameters pbeParameters, System.Span<byte> destination, out int bytesWritten) { throw null; }
public virtual bool TryExportEncryptedPkcs8PrivateKey(System.ReadOnlySpan<char> password, System.Security.Cryptography.PbeParameters pbeParameters, System.Span<byte> destination, out int bytesWritten) { throw null; }
public bool TryExportEncryptedPkcs8PrivateKeyPem(System.ReadOnlySpan<char> password, System.Security.Cryptography.PbeParameters pbeParameters, System.Span<char> destination, out int charsWritten) { throw null; }
public virtual bool TryExportPkcs8PrivateKey(System.Span<byte> destination, out int bytesWritten) { throw null; }
public bool TryExportPkcs8PrivateKeyPem(System.Span<char> destination, out int charsWritten) { throw null; }
public virtual bool TryExportSubjectPublicKeyInfo(System.Span<byte> destination, out int bytesWritten) { throw null; }
public bool TryExportSubjectPublicKeyInfoPem(System.Span<char> destination, out int charsWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public abstract partial class AsymmetricKeyExchangeFormatter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
Link="Common\System\Obsoletions.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\Helpers.cs"
Link="Internal\Cryptography\Helpers.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\PemKeyImportHelpers.cs"
Link="Internal\Cryptography\PemKeyImportHelpers.cs" />
<Compile Include="$(CommonPath)Internal\Cryptography\PemKeyHelpers.cs"
Link="Internal\Cryptography\PemKeyHelpers.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\CryptoPool.cs"
Link="Common\System\Security\Cryptography\CryptoPool.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\KeySizeHelpers.cs"
Expand Down
Loading

0 comments on commit 2099752

Please sign in to comment.