LibAC-dart/lib/encryption/rsa.dart

151 lines
3.8 KiB
Dart

import 'dart:typed_data';
import 'dart:math';
class RSA {
final RSAPublicKey publicKey;
final RSAPrivateKey privateKey;
RSA._(this.publicKey, this.privateKey);
static RSA generate({int keySize = 2048}) {
final random = Random.secure();
// Generate RSA Key Pair
final p = _generatePrime(keySize ~/ 2, random);
final q = _generatePrime(keySize ~/ 2, random);
final n = p * q;
final phi = (p - BigInt.one) * (q - BigInt.one);
final e = BigInt.from(65537); // Common public exponent
final d = _modInverse(e, phi);
final publicKey = RSAPublicKey(n, e);
final privateKey = RSAPrivateKey(n, d);
return RSA._(publicKey, privateKey);
}
static RSA fromKeyPair(RSAPrivateKey priv, RSAPublicKey pub) {
RSA rsa = RSA._(pub, priv);
return rsa;
}
Uint8List encrypt(Uint8List data) {
return publicKey.encrypt(data);
}
Uint8List decrypt(Uint8List encryptedData) {
return privateKey.decrypt(encryptedData);
}
Uint8List sign(Uint8List data) {
return privateKey.sign(data);
}
bool verify(Uint8List data, Uint8List signature) {
return publicKey.verify(data, signature);
}
static BigInt _generatePrime(int bitLength, Random random) {
while (true) {
final candidate = BigInt.from(random.nextInt(1 << (bitLength - 1)) | 1);
if (_isPrime(candidate)) {
return candidate;
}
}
}
static bool _isPrime(BigInt n) {
if (n < BigInt.two) return false;
for (BigInt i = BigInt.two; i * i <= n; i += BigInt.one) {
if (n % i == BigInt.zero) return false;
}
return true;
}
static BigInt _modInverse(BigInt a, BigInt m) {
BigInt m0 = m;
BigInt y = BigInt.zero, x = BigInt.one;
while (a > BigInt.one) {
BigInt q = a ~/ m;
BigInt t = m;
m = a % m;
a = t;
t = y;
y = x - q * y;
x = t;
}
if (x < BigInt.zero) {
x += m0;
}
return x;
}
}
class RSAPublicKey {
final BigInt modulus;
final BigInt exponent;
RSAPublicKey(this.modulus, this.exponent);
Uint8List encrypt(Uint8List data) {
final message = BigInt.parse(
data.toList().map((b) => b.toRadixString(16).padLeft(2, '0')).join(),
radix: 16);
final encrypted = message.modPow(exponent, modulus);
return Uint8List.fromList(encrypted
.toRadixString(16)
.padLeft((modulus.bitLength + 7) ~/ 8 * 2, '0')
.codeUnits);
}
bool verify(Uint8List data, Uint8List signature) {
final signedBigInt = BigInt.parse(
signature
.toList()
.map((b) => b.toRadixString(16).padLeft(2, '0'))
.join(),
radix: 16);
final decryptedSignature = signedBigInt.modPow(exponent, modulus);
final message = BigInt.parse(
data.toList().map((b) => b.toRadixString(16).padLeft(2, '0')).join(),
radix: 16);
return message == decryptedSignature;
}
}
class RSAPrivateKey {
final BigInt modulus;
final BigInt exponent;
RSAPrivateKey(this.modulus, this.exponent);
Uint8List decrypt(Uint8List encryptedData) {
final encryptedBigInt = BigInt.parse(
encryptedData
.toList()
.map((b) => b.toRadixString(16).padLeft(2, '0'))
.join(),
radix: 16);
final decrypted = encryptedBigInt.modPow(exponent, modulus);
return Uint8List.fromList(decrypted
.toRadixString(16)
.padLeft((modulus.bitLength + 7) ~/ 8 * 2, '0')
.codeUnits);
}
Uint8List sign(Uint8List data) {
final message = BigInt.parse(
data.toList().map((b) => b.toRadixString(16).padLeft(2, '0')).join(),
radix: 16);
final signed = message.modPow(exponent, modulus);
return Uint8List.fromList(signed
.toRadixString(16)
.padLeft((modulus.bitLength + 7) ~/ 8 * 2, '0')
.codeUnits);
}
}