151 lines
3.8 KiB
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);
|
|
}
|
|
}
|