66 lines
2.1 KiB
C#
66 lines
2.1 KiB
C#
|
|
using System.Security.Cryptography;
|
||
|
|
using IdentityShroud.Core.Contracts;
|
||
|
|
using IdentityShroud.Core.Security.Keys;
|
||
|
|
|
||
|
|
namespace IdentityShroud.Core.Model;
|
||
|
|
|
||
|
|
public sealed class DecryptedSigningKey : IDisposable
|
||
|
|
{
|
||
|
|
private readonly byte[] _keyData;
|
||
|
|
private readonly int _keyLength;
|
||
|
|
private bool _disposed;
|
||
|
|
|
||
|
|
public RealmSigningKeyId Id { get; }
|
||
|
|
public KeyType KeyType { get; }
|
||
|
|
public ReadOnlySpan<byte> KeyData => _disposed
|
||
|
|
? throw new ObjectDisposedException(nameof(DecryptedSigningKey))
|
||
|
|
: _keyData.AsSpan(0, _keyLength);
|
||
|
|
|
||
|
|
public DecryptedSigningKey(RealmSigningKey realmSigningKey, IDekEncryptionService encryptionService)
|
||
|
|
{
|
||
|
|
Id = realmSigningKey.Id;
|
||
|
|
KeyType = realmSigningKey.KeyType;
|
||
|
|
int keySize = encryptionService.GetDecryptedSize(realmSigningKey.Key);
|
||
|
|
_keyData = GC.AllocateArray<byte>(keySize, pinned: true);
|
||
|
|
_keyLength = keySize;
|
||
|
|
encryptionService.Decrypt(realmSigningKey.Key, _keyData);
|
||
|
|
}
|
||
|
|
|
||
|
|
public DecryptedSigningKey()
|
||
|
|
{
|
||
|
|
Id = RealmSigningKeyId.NewId();
|
||
|
|
KeyType = KeyType.RSA;
|
||
|
|
const int keySize = 2048;
|
||
|
|
|
||
|
|
using var rsa = RSA.Create();
|
||
|
|
rsa.KeySize = keySize;
|
||
|
|
int estimatedSize = EstimatePkcs8ExportSize(keySize);
|
||
|
|
|
||
|
|
Span<byte> temp = stackalloc byte[estimatedSize * 2];
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (!rsa.TryExportPkcs8PrivateKey(temp, out int bytesWritten))
|
||
|
|
throw new CryptographicException("Unable to export RSA private key.");
|
||
|
|
|
||
|
|
_keyData = GC.AllocateArray<byte>(bytesWritten, pinned: true);
|
||
|
|
_keyLength = bytesWritten;
|
||
|
|
temp[..bytesWritten].CopyTo(_keyData);
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
CryptographicOperations.ZeroMemory(temp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
if (_disposed) return;
|
||
|
|
_disposed = true;
|
||
|
|
CryptographicOperations.ZeroMemory(_keyData);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Note actual accurate coefficients would be *0.566 and +57.4
|
||
|
|
public static int EstimatePkcs8ExportSize(int keySizeBits)
|
||
|
|
=> ((keySizeBits * 6) / 10) + 150;
|
||
|
|
}
|