Skip to content

Commit

Permalink
feat: Better Pem parsing (#186)
Browse files Browse the repository at this point in the history
A PEM may only have one object.
  • Loading branch information
seebees authored Apr 21, 2023
1 parent 4b74b39 commit 5abf251
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 46 deletions.
45 changes: 35 additions & 10 deletions AwsCryptographyPrimitives/runtimes/net/Extern/RSAEncryption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ private static IAsymmetricBlockCipher GetEngineForPadding(_IRSAPaddingMode paddi
// key and returns the AsymmetricKeyParameter for that public key, encoded using UTF-8
private static AsymmetricKeyParameter GetPublicKeyFromByteSeq(ibyteseq key) {
AsymmetricKeyParameter keyParam;
using (var stringReader = new StringReader(Encoding.UTF8.GetString(key.Elements))) {
using (var stringReader = new StringReader(Encoding.UTF8.GetString(key.CloneAsArray()))) {
return (AsymmetricKeyParameter) new PemReader(stringReader).ReadObject();
}
}
Expand Down Expand Up @@ -149,8 +149,9 @@ public static _IResult<ibyteseq, _IError> EncryptExtern(_IRSAPaddingMode padding
IAsymmetricBlockCipher engine = GetEngineForPadding(padding);
AsymmetricKeyParameter publicKeyParam = GetPublicKeyFromByteSeq(publicKey);
engine.Init(true, publicKeyParam);
var plaintextMessageBytes = plaintextMessage.CloneAsArray();
return Result<ibyteseq, _IError>.create_Success(byteseq.FromArray(
engine.ProcessBlock(plaintextMessage.Elements, 0, plaintextMessage.Elements.Length)));
engine.ProcessBlock(plaintextMessageBytes, 0, plaintextMessageBytes.Length)));
}
catch (Exception encryptEx) {
return Result<ibyteseq, _IError>
Expand All @@ -161,20 +162,44 @@ public static _IResult<ibyteseq, _IError> EncryptExtern(_IRSAPaddingMode padding
public static _IResult<ibyteseq, _IError> DecryptExtern(_IRSAPaddingMode padding, ibyteseq privateKey, ibyteseq cipherText) {
try {
IAsymmetricBlockCipher engine = GetEngineForPadding(padding);
AsymmetricCipherKeyPair keyPair;
using ( var stringReader = new StringReader(Encoding.UTF8.GetString(privateKey.Elements))) {
// This needs to be read as an AsymmetricCipherKeyPair and cannot be read directly as a
// AsymmetricKeyParameter like the public key can
keyPair = (AsymmetricCipherKeyPair) new PemReader(stringReader).ReadObject();
}
engine.Init(false, keyPair.Private);
AsymmetricKeyParameter privateKeyParameters = GetPrivateKeyFromByteSeq(privateKey.CloneAsArray());
engine.Init(false, privateKeyParameters);
var cipherTextBytes = cipherText.CloneAsArray();
return Result<ibyteseq, _IError>.create_Success(byteseq.FromArray(
engine.ProcessBlock(cipherText.Elements, 0, cipherText.Elements.Length)));
engine.ProcessBlock(cipherTextBytes, 0, cipherTextBytes.Length)));
}
catch (Exception decryptEx) {
return Result<ibyteseq, _IError>
.create_Failure(new Error_Opaque(decryptEx));
}
}

/// <summary>
/// Reads the given PEM-encoded private key, and returns the corresponding AsymmetricKeyParameter.
/// This is complicated because a PEM MAY contain both keys as a pair
/// or MAY only contain the private key.
/// </summary>
public static AsymmetricKeyParameter GetPrivateKeyFromByteSeq(
byte[] pemDataBlob
) {
using ( var stringReader = new StringReader(Encoding.UTF8.GetString(pemDataBlob))) {

switch (new PemReader(stringReader).ReadObject())
{
// These casts are for correctness.
// This is to return RSA parameters,
// and these two types both extend from AsymmetricKeyParameter.
// But also other things do as well (elliptic curves),
// these checks are to make sure that we only get RSA keys back.
case AsymmetricCipherKeyPair keypair:
var keyParams = (RsaPrivateCrtKeyParameters)keypair.Private;
return keyParams;
case RsaKeyParameters keyParameter:
return keyParameter;
default:
throw new ArgumentException("PEM does not contain an RSA private key.");
}
}
}
}
}
Loading

0 comments on commit 5abf251

Please sign in to comment.