Skip to content

Commit

Permalink
Do not unnecessarily pad RSA exponent length to 4 bytes (Azure#8381)
Browse files Browse the repository at this point in the history
  • Loading branch information
heaths authored Oct 25, 2019
1 parent 2f99f34 commit 2e0bc39
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ public RSA ToRSA(bool includePrivateParameters = false)
// Key parameter length requirements defined by 2.2.2.9.1 RSA Private Key BLOB specification: https://docs.microsoft.com/openspecs/windows_protocols/ms-wcce/5cf2e6b9-3195-4f85-bc18-05b50e6d4e11
var rsaParameters = new RSAParameters
{
Exponent = ForceBufferLength(nameof(E), E, 4),
Exponent = E,
Modulus = TrimBuffer(N),
};

Expand Down
55 changes: 47 additions & 8 deletions sdk/keyvault/Azure.Security.KeyVault.Keys/tests/JsonWebKeyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Azure.Core;
using NUnit.Framework;

Expand Down Expand Up @@ -40,12 +41,22 @@ public void SerializeOctet()
[Test]
public void ToAes()
{
byte[] plaintext = Encoding.UTF8.GetBytes("test");

using Aes aes = Aes.Create();
using ICryptoTransform encryptor = aes.CreateEncryptor();
byte[] ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);

JsonWebKey jwk = new JsonWebKey(aes);
CollectionAssert.AreEqual(aes.Key, jwk.K);
Assert.True(HasPrivateKey(jwk));

Aes key = jwk.ToAes();
using Aes key = jwk.ToAes();
CollectionAssert.AreEqual(jwk.K, key.Key);

using ICryptoTransform decryptor = key.CreateDecryptor(key.Key, aes.IV);
plaintext = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
Assert.AreEqual("test", Encoding.UTF8.GetString(plaintext));
}

[Test]
Expand Down Expand Up @@ -161,13 +172,34 @@ public void ToECDsa(string oid, string friendlyName, bool includePrivateParamete
#if NET461
Assert.Ignore("Creating ECDsa with JsonWebKey is not supported on net461.");
#else
byte[] plaintext = Encoding.UTF8.GetBytes("test");
byte[] signature = null;

using ECDsa ecdsa = ECDsa.Create();
int bitLength = ecdsa.KeySize;
try
{
ecdsa.GenerateKey(ECCurve.CreateFromValue(oid));
}
catch (NotSupportedException)
{
Assert.Inconclusive("This platform does not support OID {0} with friendly name '{1}'", oid, friendlyName);
}

if (includePrivateParameters)
{
signature = ecdsa.SignData(plaintext, HashAlgorithmName.SHA256);
}

JsonWebKey jwk = new JsonWebKey(ecdsa, includePrivateParameters);

ECDsa key = jwk.ToECDsa(includePrivateParameters);
using ECDsa key = jwk.ToECDsa(includePrivateParameters);
int bitLength = ecdsa.KeySize;
Assert.AreEqual(bitLength, key.KeySize);

if (signature != null)
{
Assert.IsTrue(ecdsa.VerifyData(plaintext, signature, HashAlgorithmName.SHA256));
}
#endif
}

Expand Down Expand Up @@ -270,13 +302,24 @@ public void ToRSANoPrivateKey()
[TestCase(true)]
public void ToRSA(bool includePrivateParameters)
{
byte[] plaintext = Encoding.UTF8.GetBytes("test");

using RSA rsa = RSA.Create();
byte[] ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.Pkcs1);

JsonWebKey jwk = new JsonWebKey(rsa, includePrivateParameters);

int bitLength = jwk.N.Length * 8;
Assert.AreEqual(includePrivateParameters, HasPrivateKey(jwk));

RSA key = jwk.ToRSA(includePrivateParameters);
using RSA key = jwk.ToRSA(includePrivateParameters);
Assert.AreEqual(bitLength, key.KeySize);

if (includePrivateParameters)
{
plaintext = key.Decrypt(ciphertext, RSAEncryptionPadding.Pkcs1);
Assert.AreEqual("test", Encoding.UTF8.GetString(plaintext));
}
}

[Test]
Expand Down Expand Up @@ -366,10 +409,6 @@ private static IEnumerable<object> GetRSAInvalidKeyData()
zeroE.Exponent = new byte[] { 0, 0, 0, 0 };
yield return new object[] { zeroE, nameof(zeroE) };

RSAParameters longerE = rsaParameters;
longerE.Exponent = new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5 };
yield return new object[] { longerE, nameof(longerE) };

RSAParameters nullN = rsaParameters;
nullN.Modulus = null;
yield return new object[] { nullN, nameof(nullE) };
Expand Down

0 comments on commit 2e0bc39

Please sign in to comment.