From 7620058711e322bdba9a1a882b60a69c8253c106 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Thu, 12 Dec 2024 22:10:37 +0100 Subject: [PATCH] PrivateKeyCredential: fix issue when loading some RSA keys. --- src/Tmds.Ssh/BigIntegerExtensions.cs | 19 +++++++++++++++++++ src/Tmds.Ssh/PrivateKeyParser.OpenSsh.cs | 17 +++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 src/Tmds.Ssh/BigIntegerExtensions.cs diff --git a/src/Tmds.Ssh/BigIntegerExtensions.cs b/src/Tmds.Ssh/BigIntegerExtensions.cs new file mode 100644 index 0000000..bfd89c7 --- /dev/null +++ b/src/Tmds.Ssh/BigIntegerExtensions.cs @@ -0,0 +1,19 @@ +namespace Tmds.Ssh; + +static class BigIntegerExtensions +{ + public static byte[] ToBEByteArray(this BigInteger integer, bool isUnsigned, int minLength) + { + int bytesNeeded = integer.GetByteCount(isUnsigned); + int length = Math.Max(bytesNeeded, minLength); + byte[] array = new byte[length]; + int prefixLength = length - bytesNeeded; + bool success = integer.TryWriteBytes(array.AsSpan(prefixLength), out _, isUnsigned, isBigEndian: true); + Debug.Assert(success); // Can't fail since the array is large enough. + if (prefixLength != 0 && integer.Sign < 0) + { + array.AsSpan(0, prefixLength).Fill(0xff); + } + return array; + } +} \ No newline at end of file diff --git a/src/Tmds.Ssh/PrivateKeyParser.OpenSsh.cs b/src/Tmds.Ssh/PrivateKeyParser.OpenSsh.cs index e7ab4bd..8d0fc79 100644 --- a/src/Tmds.Ssh/PrivateKeyParser.OpenSsh.cs +++ b/src/Tmds.Ssh/PrivateKeyParser.OpenSsh.cs @@ -168,10 +168,14 @@ uint32 rounds private static PrivateKey ParseOpenSshRsaKey(SequenceReader reader) { + // .NET RSA's class has some length expectations: + // D must have the same length as Modulus. + // P, Q, DP, DQ, and InverseQ must have half the length of Modulus rounded up. byte[] modulus = reader.ReadMPIntAsByteArray(isUnsigned: true); + int halfLength = (modulus.Length + 1) / 2; byte[] exponent = reader.ReadMPIntAsByteArray(isUnsigned: true); BigInteger d = reader.ReadMPInt(); - byte[] inverseQ = reader.ReadMPIntAsByteArray(isUnsigned: true); + byte[] inverseQ = reader.ReadMPIntAsByteArray(isUnsigned: true, minLength: halfLength); BigInteger p = reader.ReadMPInt(); BigInteger q = reader.ReadMPInt(); @@ -182,12 +186,13 @@ private static PrivateKey ParseOpenSshRsaKey(SequenceReader reader) { Modulus = modulus, Exponent = exponent, - D = d.ToByteArray(isUnsigned: true, isBigEndian: true), + D = d.ToBEByteArray(isUnsigned: true, minLength: modulus.Length), InverseQ = inverseQ, - P = p.ToByteArray(isUnsigned: true, isBigEndian: true), - Q = q.ToByteArray(isUnsigned: true, isBigEndian: true), - DP = dp.ToByteArray(isUnsigned: true, isBigEndian: true), - DQ = dq.ToByteArray(isUnsigned: true, isBigEndian: true) + + P = p.ToBEByteArray(isUnsigned: true, minLength: halfLength), + Q = q.ToBEByteArray(isUnsigned: true, minLength: halfLength), + DP = dp.ToBEByteArray(isUnsigned: true, minLength: halfLength), + DQ = dq.ToBEByteArray(isUnsigned: true, minLength: halfLength) }; RSA rsa = RSA.Create(); try