SecuCore/Security/RSAPublicKey.cs
2026-03-03 23:53:04 -05:00

109 lines
No EOL
3.7 KiB
C#

/*
* Secucore
*
* Copyright (C) 2023 Trevor Hall
* All rights reserved.
*
* This software may be modified and distributed under the terms
* of the MIT license.
*
*/
using System;
using System.Numerics;
namespace SecuCore.Security
{
public class RSAPublicKey
{
public int keysize;
public byte[] keydat;
public byte[] modulusbytes;
public byte[] exponentbytes;
public RSAPublicKey(byte[] dat, int offset = 0)
{
keydat = dat;
int dp = offset;
Asn1Info ai = DerDecoder.GetAsn1Data(dat, ref dp);
if (ai.type != Asn1Type.SEQUENCE) throw new AsnException("Malformed RSA key");
ai = DerDecoder.GetAsn1Data(dat, ref dp);
if (ai.type != Asn1Type.INTEGER) throw new AsnException("Malformed RSA key");
modulusbytes = new byte[ai.length - 1];
Buffer.BlockCopy(dat, ai.contentOffset + 1, modulusbytes, 0, ai.length - 1);
keysize = modulusbytes.Length;
dp += ai.length;
ai = DerDecoder.GetAsn1Data(dat, ref dp);
if (ai.type != Asn1Type.INTEGER) throw new AsnException("Malformed RSA key");
exponentbytes = new byte[ai.length];
Buffer.BlockCopy(dat, ai.contentOffset, exponentbytes, 0, ai.length);
}
public byte[] EncryptData(byte[] data)
{
SecRNG sr = new SecRNG();
BigInteger modulus = new BigInteger(modulusbytes, true, true);
BigInteger exponent = new BigInteger(exponentbytes, true, true);
byte[] block = new byte[keysize];
byte[] brng = new byte[keysize];
int bp = 0;
while (bp < keysize)
{
sr.GetRandomBytes(brng, 0, brng.Length);
for(int i = 0; i < brng.Length; i++)
{
if (brng[i] > 2) block[bp++] = brng[i];
if (bp >= keysize) break;
}
}
block[0] = 0x00;
block[1] = 0x02;
block[block.Length - data.Length - 1] = 0x00;
Buffer.BlockCopy(data, 0, block, block.Length - data.Length, data.Length);
BigInteger B = new BigInteger(block, true, true);
BigInteger D = ModPow(B, exponent, modulus);
byte[] bigendian = D.ToByteArray(true, true);
return bigendian;
}
public byte[] DecryptSignature(byte[] signature)
{
BigInteger modulus = new BigInteger(modulusbytes, true, true);
BigInteger exponent = new BigInteger(exponentbytes, true, true);
BigInteger B = new BigInteger(signature, true, true);
BigInteger D = ModPow(B, exponent, modulus);
byte[] bigendian = D.ToByteArray(false, true);
int start = 0;
for(int i = 0; i < bigendian.Length; i++)
{
if(bigendian[i] == 0)
{
start = i + 1;
break;
}
}
byte[] cropped = new byte[bigendian.Length - start];
Buffer.BlockCopy(bigendian, start, cropped, 0, bigendian.Length - start);
return cropped;
}
private static BigInteger ModPow(BigInteger basenum, BigInteger exponent, BigInteger modulus)
{
if (modulus == 1) return 0;
BigInteger curPow = basenum % modulus;
BigInteger res = 1;
while (exponent > 0)
{
if ((exponent & 0x01) == 1) res = (res * curPow) % modulus;
exponent >>= 1;
curPow = (curPow * curPow) % modulus;
}
return res;
}
}
}