Add Mono compatibility for RSA-PSS

This commit is contained in:
Alex Barney 2018-12-19 20:06:04 -06:00
parent 9c3ddf11fb
commit d29f7b27a7
2 changed files with 73 additions and 1 deletions

62
src/LibHac/Compat.cs Normal file
View file

@ -0,0 +1,62 @@
#if NETFRAMEWORK
using System;
using System.Numerics;
using System.Security.Cryptography;
namespace LibHac
{
internal class Compat
{
public static bool IsMono { get; } = Type.GetType("Mono.Runtime") != null;
public static bool Rsa2048PssVerifyMono(byte[] data, byte[] signature, byte[] modulus)
{
const int rsaLen = 0x100;
const int digestLen = 0x20;
const int hashOffset = rsaLen - digestLen - 1;
const int saltOffset = hashOffset - digestLen;
const int padEnd = saltOffset - 1;
SHA256 sha = SHA256.Create();
var message = new byte[rsaLen];
BigInteger decInt = BigInteger.ModPow(Crypto.GetBigInteger(signature), new BigInteger(65537), Crypto.GetBigInteger(modulus));
byte[] decBytes = decInt.ToByteArray();
if (decBytes[0] != 0xBC) return false;
Array.Reverse(decBytes);
Array.Copy(decBytes, 0, message, message.Length - decBytes.Length, decBytes.Length);
var hashBuf = new byte[0x24];
Array.Copy(message, hashOffset, hashBuf, 0, digestLen);
ref byte seed = ref hashBuf[0x23];
for (int i = 0; i < hashOffset; i += 0x20)
{
Util.XorArrays(message.AsSpan(i, digestLen), sha.ComputeHash(hashBuf));
seed++;
}
message[0] &= 0x7F;
if (!Util.IsEmpty(message.AsSpan(0, padEnd)) || message[padEnd] != 1)
{
return false;
}
var prefix = new byte[8];
byte[] digest = sha.ComputeHash(data);
sha.TransformBlock(prefix, 0, prefix.Length, null, 0);
sha.TransformBlock(digest, 0, digestLen, null, 0);
sha.TransformFinalBlock(message, saltOffset, digestLen);
return Util.SpansEqual(hashBuf.AsSpan(0, 0x20), sha.Hash);
}
}
}
#endif

View file

@ -94,7 +94,7 @@ namespace LibHac
}
}
private static BigInteger GetBigInteger(byte[] bytes)
internal static BigInteger GetBigInteger(byte[] bytes)
{
var signPadded = new byte[bytes.Length + 1];
Buffer.BlockCopy(bytes, 0, signPadded, 1, bytes.Length);
@ -156,6 +156,15 @@ namespace LibHac
public static Validity Rsa2048PssVerify(byte[] data, byte[] signature, byte[] modulus)
{
#if NETFRAMEWORK
if (true)
{
return Compat.Rsa2048PssVerifyMono(data, signature, modulus)
? Validity.Valid
: Validity.Invalid;
}
#endif
#if USE_RSA_CNG
using (RSA rsa = new RSACng())
#else
@ -172,6 +181,7 @@ namespace LibHac
public static byte[] DecryptTitleKey(byte[] titleKeyblock, RSAParameters rsaParams)
{
// todo: Does this work on Mono?
#if USE_RSA_CNG
RSA rsa = new RSACng();
#else