Files
AndroidDebugBridge/AndroidDebugBridgeCryptography.cs
2024-03-03 00:27:52 +01:00

171 lines
5.4 KiB
C#

/*
* MIT License
*
* Copyright (c) 2024 The DuoWOA authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System.IO;
using System.Numerics;
using System.Security.Cryptography;
namespace AndroidDebugBridge
{
internal class AndroidDebugBridgeCryptography
{
private static BigInteger EGCD(BigInteger left,
BigInteger right,
out BigInteger leftFactor,
out BigInteger rightFactor)
{
leftFactor = 0;
rightFactor = 1;
BigInteger u = 1;
BigInteger v = 0;
BigInteger gcd = 0;
while (left != 0)
{
BigInteger q = right / left;
BigInteger r = right % left;
BigInteger m = leftFactor - (u * q);
BigInteger n = rightFactor - (v * q);
right = left;
left = r;
leftFactor = u;
rightFactor = v;
u = m;
v = n;
gcd = right;
}
return gcd;
}
private static BigInteger ModInverse(BigInteger value, BigInteger modulo)
{
BigInteger egcd = EGCD(value, modulo, out BigInteger x, out _);
if (1 != egcd)
{
//throw new ArgumentException("Invalid modulo", nameof(modulo));
}
if (x < 0)
{
x += modulo;
}
return x % modulo;
}
internal static byte[] ADBRSAToBuffer(uint n0inv, uint[] n, uint[] rr, int exponent)
{
int len = n.Length;
byte[] buffer = new byte[12 + (8 * len)];
using MemoryStream memoryStream = new(buffer);
using BinaryWriter binaryWriter = new(memoryStream);
binaryWriter.Write(len);
binaryWriter.Write(n0inv);
foreach (uint nElement in n)
{
binaryWriter.Write(nElement);
}
foreach (uint rrElement in rr)
{
binaryWriter.Write(rrElement);
}
binaryWriter.Write(exponent);
return buffer;
}
internal static (uint n0inv, uint[] n, uint[] rr, int exponent) BufferToADBRSA(byte[] buffer)
{
using MemoryStream memoryStream = new(buffer);
using BinaryReader binaryReader = new(memoryStream);
int len = binaryReader.ReadInt32();
if (buffer.Length != 12 + (8 * len))
{
throw new InvalidDataException("Invalid ADB RSA Buffer!");
}
uint n0inv = binaryReader.ReadUInt32();
uint[] n = new uint[len];
for (int i = 0; i < len; i++)
{
n[i] = binaryReader.ReadUInt32();
}
uint[] rr = new uint[len];
for (int i = 0; i < len; i++)
{
rr[i] = binaryReader.ReadUInt32();
}
int exponent = binaryReader.ReadInt32();
return (n0inv, n, rr, exponent);
}
internal static (uint n0inv, uint[] n, uint[] rr, int exponent) ConvertRSAToADBRSA(RSAParameters publicKeyParameters)
{
byte[] modulus = publicKeyParameters.Modulus!;
byte[] exponent = publicKeyParameters.Exponent!;
const int keyLengthInDWORDs = 64; // 2048 bits / 256 bytes / 64 DWORDs
int e = (int)new BigInteger(exponent);
BigInteger r32 = new BigInteger(1) << 32;
BigInteger n = new(modulus);
BigInteger r = new BigInteger(1) << (keyLengthInDWORDs * 32);
BigInteger rr = BigInteger.ModPow(r, new BigInteger(2), n);
BigInteger remainder = BigInteger.Remainder(n, r32);
BigInteger tn0inv = ModInverse(remainder, r32);
uint n0inv = (uint)(BigInteger.Negate(tn0inv) & uint.MaxValue);
uint[] nTable = new uint[keyLengthInDWORDs];
uint[] rrTable = new uint[keyLengthInDWORDs];
for (int i = 0; i < keyLengthInDWORDs; i++)
{
rr = BigInteger.DivRem(rr, r32, out remainder);
rrTable[i] = (uint)remainder;
n = BigInteger.DivRem(n, r32, out remainder);
nTable[i] = (uint)(remainder & uint.MaxValue);
}
return (n0inv, nTable, rrTable, e);
}
}
}