Finish implementing some encryption in the network protocols with AES
This commit is contained in:
parent
38eb7c6acd
commit
84cef345eb
10 changed files with 263 additions and 391 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -32,3 +32,6 @@ doc/api/
|
|||
*.iml
|
||||
|
||||
out
|
||||
|
||||
test/aesKey.bin
|
||||
test/HelloWorld.*
|
|
@ -1,3 +1,3 @@
|
|||
class Constants {
|
||||
static const VERSION = "1.3.010525+0414";
|
||||
static const VERSION = "1.3.010625+0228";
|
||||
}
|
||||
|
|
|
@ -1,80 +1,55 @@
|
|||
import 'dart:typed_data';
|
||||
import 'dart:math';
|
||||
|
||||
class AES {
|
||||
import 'package:encrypt/encrypt.dart';
|
||||
|
||||
class AESData {
|
||||
final List<int> iv;
|
||||
final List<int> data;
|
||||
|
||||
AESData({required this.iv, required this.data});
|
||||
}
|
||||
|
||||
class AESCipher {
|
||||
final Uint8List _aesKey;
|
||||
|
||||
AES._(this._aesKey);
|
||||
AESCipher._(this._aesKey);
|
||||
|
||||
static Future<AES> generate({int aesKeySize = 256}) async {
|
||||
final random = Random.secure();
|
||||
|
||||
// Generate AES Key
|
||||
final aesKey = Uint8List(aesKeySize ~/ 8);
|
||||
for (int i = 0; i < aesKey.length; i++) {
|
||||
aesKey[i] = random.nextInt(256);
|
||||
static Future<AESCipher> generate({int aesKeySize = 256}) async {
|
||||
return AESCipher._(Key.fromLength(aesKeySize ~/ 8).bytes);
|
||||
}
|
||||
|
||||
return AES._(aesKey);
|
||||
}
|
||||
|
||||
static AES useKey(Uint8List key) {
|
||||
AES aes = AES._(key);
|
||||
|
||||
return aes;
|
||||
static AESCipher useKey(Uint8List key) {
|
||||
return AESCipher._(key);
|
||||
}
|
||||
|
||||
Uint8List getKey() {
|
||||
return Uint8List.fromList(_aesKey);
|
||||
}
|
||||
|
||||
Uint8List encrypt(Uint8List data) {
|
||||
return _aesEncrypt(data, _aesKey);
|
||||
Future<AESData> encrypt(Uint8List data) async {
|
||||
final iv = IV.fromLength(16); // Generate a random 16-byte IV
|
||||
final encryptedData = await _aesEncrypt(data, _aesKey, iv);
|
||||
|
||||
return AESData(iv: iv.bytes.toList(), data: encryptedData.toList());
|
||||
}
|
||||
|
||||
Uint8List decrypt(Uint8List encryptedData) {
|
||||
return _aesDecrypt(encryptedData, _aesKey);
|
||||
Future<Uint8List> decrypt(AESData data) async {
|
||||
final iv = IV(Uint8List.fromList(data.iv));
|
||||
return _aesDecrypt(Uint8List.fromList(data.data), _aesKey, iv);
|
||||
}
|
||||
|
||||
static Uint8List _aesEncrypt(Uint8List data, Uint8List key) {
|
||||
final blockSize = 16;
|
||||
final paddedData = _pad(data, blockSize);
|
||||
final encrypted = Uint8List(paddedData.length);
|
||||
static Future<Uint8List> _aesEncrypt(
|
||||
Uint8List data, Uint8List key, IV iv) async {
|
||||
var aes = Encrypter(AES(Key(key), mode: AESMode.cbc));
|
||||
|
||||
for (int i = 0; i < paddedData.length; i += blockSize) {
|
||||
for (int j = 0; j < blockSize; j++) {
|
||||
encrypted[i + j] = paddedData[i + j] ^ key[j % key.length];
|
||||
}
|
||||
final encrypted = await aes.encryptBytes(data.toList(), iv: iv);
|
||||
return encrypted.bytes;
|
||||
}
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
static Uint8List _aesDecrypt(Uint8List data, Uint8List key) {
|
||||
final blockSize = 16;
|
||||
final decrypted = Uint8List(data.length);
|
||||
|
||||
for (int i = 0; i < data.length; i += blockSize) {
|
||||
for (int j = 0; j < blockSize; j++) {
|
||||
decrypted[i + j] = data[i + j] ^ key[j % key.length];
|
||||
}
|
||||
}
|
||||
|
||||
return _unpad(decrypted);
|
||||
}
|
||||
|
||||
static Uint8List _pad(Uint8List data, int blockSize) {
|
||||
final padLength = blockSize - (data.length % blockSize);
|
||||
final paddedData = Uint8List(data.length + padLength);
|
||||
paddedData.setAll(0, data);
|
||||
for (int i = data.length; i < paddedData.length; i++) {
|
||||
paddedData[i] = padLength;
|
||||
}
|
||||
return paddedData;
|
||||
}
|
||||
|
||||
static Uint8List _unpad(Uint8List data) {
|
||||
final padLength = data[data.length - 1];
|
||||
return Uint8List.sublistView(data, 0, data.length - padLength);
|
||||
static Future<Uint8List> _aesDecrypt(
|
||||
Uint8List data, Uint8List key, IV iv) async {
|
||||
final aes = Encrypter(AES(Key(key), mode: AESMode.cbc));
|
||||
final decrypted = await aes.decryptBytes(Encrypted(data), iv: iv);
|
||||
return Uint8List.fromList(decrypted);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
155
lib/encryption/xtea.dart
Normal file
155
lib/encryption/xtea.dart
Normal file
|
@ -0,0 +1,155 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:libac_dart/utils/Hashing.dart';
|
||||
|
||||
class XTEA {
|
||||
static const int XTEA_DELTA = 0x9E3779B9; // (sqrt(5) - 1) * 2^31
|
||||
static const int xteaNumRounds = 6;
|
||||
List<int> _xteaKey = [0, 0, 0, 0];
|
||||
|
||||
/// Used as part of testsuite to compare provided keys.
|
||||
///
|
||||
/// This function will sequentially check each entry.
|
||||
///
|
||||
/// Returns: -1 on success, or which entry failed verification.
|
||||
///
|
||||
/// On failure it will print to the console what failed
|
||||
int testKey(List<int> key) {
|
||||
for (int i = 0; i < key.length; i++) {
|
||||
int v0 = _xteaKey[i];
|
||||
int v1 = key[i];
|
||||
|
||||
if (v0 != v1) {
|
||||
print(
|
||||
"FATAL: TestKey XTEA failed at position ${i}.\nExpected: ${v1}\nActual: ${v0}");
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
XTEA(String password) {
|
||||
_xteaKey = _xteaKeyFromString(password);
|
||||
}
|
||||
|
||||
List<int> _xteaKeyFromString(String str) {
|
||||
// Convert string to MD5 and split into 4 integers
|
||||
str = md5(str); // Assume md5 function exists
|
||||
return [
|
||||
int.parse(str.substring(0, 8), radix: 16),
|
||||
int.parse(str.substring(8, 16), radix: 16),
|
||||
int.parse(str.substring(16, 24), radix: 16),
|
||||
int.parse(str.substring(24, 32), radix: 16)
|
||||
];
|
||||
}
|
||||
|
||||
List<int> encipher(List<int> data) {
|
||||
int v0 = data[0];
|
||||
int v1 = data[1];
|
||||
int sum = 0;
|
||||
|
||||
for (int i = 0; i < xteaNumRounds; i++) {
|
||||
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + _xteaKey[sum & 3]);
|
||||
sum += XTEA_DELTA;
|
||||
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + _xteaKey[(sum >> 11) & 3]);
|
||||
}
|
||||
|
||||
return [v0 & 0xFFFFFFFF, v1 & 0xFFFFFFFF]; // Ensure 32-bit integers
|
||||
}
|
||||
|
||||
List<int> decipher(List<int> data) {
|
||||
int v0 = data[0];
|
||||
int v1 = data[1];
|
||||
int sum = XTEA_DELTA * xteaNumRounds;
|
||||
|
||||
for (int i = 0; i < xteaNumRounds; i++) {
|
||||
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + _xteaKey[(sum >> 11) & 3]);
|
||||
sum -= XTEA_DELTA;
|
||||
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + _xteaKey[sum & 3]);
|
||||
}
|
||||
|
||||
return [v0 & 0xFFFFFFFF, v1 & 0xFFFFFFFF]; // Ensure 32-bit integers
|
||||
}
|
||||
|
||||
String encryptString(String plaintext) {
|
||||
List<int> data = utf8.encode(plaintext).toList();
|
||||
while (data.length % 8 != 0) {
|
||||
data = [...data, 0]; // Zero padding
|
||||
}
|
||||
|
||||
List<int> encrypted = [];
|
||||
for (int i = 0; i < data.length; i += 8) {
|
||||
List<int> block = encipher([
|
||||
(data[i] << 24) |
|
||||
(data[i + 1] << 16) |
|
||||
(data[i + 2] << 8) |
|
||||
data[i + 3],
|
||||
(data[i + 4] << 24) |
|
||||
(data[i + 5] << 16) |
|
||||
(data[i + 6] << 8) |
|
||||
data[i + 7]
|
||||
]);
|
||||
encrypted.addAll([
|
||||
(block[0] >> 24) & 0xFF,
|
||||
(block[0] >> 16) & 0xFF,
|
||||
(block[0] >> 8) & 0xFF,
|
||||
block[0] & 0xFF,
|
||||
(block[1] >> 24) & 0xFF,
|
||||
(block[1] >> 16) & 0xFF,
|
||||
(block[1] >> 8) & 0xFF,
|
||||
block[1] & 0xFF
|
||||
]);
|
||||
}
|
||||
|
||||
return base64.encode(encrypted);
|
||||
}
|
||||
|
||||
String decryptString(String ciphertext) {
|
||||
List<int> data = base64.decode(ciphertext).toList();
|
||||
List<int> decrypted = [];
|
||||
|
||||
for (int i = 0; i < data.length; i += 8) {
|
||||
List<int> block = decipher([
|
||||
(data[i] << 24) |
|
||||
(data[i + 1] << 16) |
|
||||
(data[i + 2] << 8) |
|
||||
data[i + 3],
|
||||
(data[i + 4] << 24) |
|
||||
(data[i + 5] << 16) |
|
||||
(data[i + 6] << 8) |
|
||||
data[i + 7]
|
||||
]);
|
||||
decrypted.addAll([
|
||||
(block[0] >> 24) & 0xFF,
|
||||
(block[0] >> 16) & 0xFF,
|
||||
(block[0] >> 8) & 0xFF,
|
||||
block[0] & 0xFF,
|
||||
(block[1] >> 24) & 0xFF,
|
||||
(block[1] >> 16) & 0xFF,
|
||||
(block[1] >> 8) & 0xFF,
|
||||
block[1] & 0xFF
|
||||
]);
|
||||
}
|
||||
|
||||
// Find the index of the last non-zero byte
|
||||
int paddingStart = decrypted.lastIndexWhere((byte) => byte != 0);
|
||||
|
||||
// If padding was added, remove only trailing zero bytes
|
||||
if (paddingStart != -1 && paddingStart + 1 < decrypted.length) {
|
||||
decrypted = decrypted.sublist(0, paddingStart + 1);
|
||||
}
|
||||
|
||||
// Attempt to decode as UTF-8
|
||||
try {
|
||||
return utf8.decode(decrypted);
|
||||
} catch (e) {
|
||||
throw FormatException('Decrypted data is not valid UTF-8: $e');
|
||||
}
|
||||
}
|
||||
|
||||
String md5(String input) {
|
||||
return Hashing.llMD5String(input, 0);
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
class XXTEA {
|
||||
final Uint8List _key;
|
||||
|
||||
XXTEA._(this._key);
|
||||
|
||||
static Future<XXTEA> fromPassword(String password,
|
||||
{String salt = 'defaultSalt'}) async {
|
||||
final keyBytes = Uint8List.fromList(utf8.encode(password + salt));
|
||||
final key = _fixKeyLength(keyBytes);
|
||||
return XXTEA._(key);
|
||||
}
|
||||
|
||||
Uint8List encryptBytes(Uint8List data) {
|
||||
final paddedData = _padData(data);
|
||||
return _xxteaEncrypt(paddedData, _key);
|
||||
}
|
||||
|
||||
Uint8List decryptBytes(Uint8List encryptedData) {
|
||||
final decryptedData = _xxteaDecrypt(encryptedData, _key);
|
||||
return _unpadData(decryptedData);
|
||||
}
|
||||
|
||||
String encryptString(String plaintext) {
|
||||
final encryptedBytes =
|
||||
encryptBytes(Uint8List.fromList(utf8.encode(plaintext)));
|
||||
return base64.encode(encryptedBytes);
|
||||
}
|
||||
|
||||
String decryptString(String encryptedText) {
|
||||
final encryptedBytes = base64.decode(encryptedText);
|
||||
final decryptedBytes = decryptBytes(encryptedBytes);
|
||||
return utf8.decode(decryptedBytes);
|
||||
}
|
||||
|
||||
Uint8List signBytes(Uint8List data) {
|
||||
final signature = _xxteaEncrypt(data, _key);
|
||||
return signature;
|
||||
}
|
||||
|
||||
bool verifySignature(Uint8List data, Uint8List signature) {
|
||||
final expectedSignature = signBytes(data);
|
||||
return _constantTimeEquals(expectedSignature, signature);
|
||||
}
|
||||
|
||||
String signString(String data) {
|
||||
final signature = signBytes(Uint8List.fromList(utf8.encode(data)));
|
||||
return base64.encode(signature);
|
||||
}
|
||||
|
||||
bool verifyStringSignature(String data, String signature) {
|
||||
final dataBytes = Uint8List.fromList(utf8.encode(data));
|
||||
final signatureBytes = base64.decode(signature);
|
||||
return verifySignature(dataBytes, signatureBytes);
|
||||
}
|
||||
|
||||
static Uint8List _fixKeyLength(Uint8List key) {
|
||||
final fixedKey = Uint8List(16);
|
||||
for (int i = 0; i < key.length && i < 16; i++) {
|
||||
fixedKey[i] = key[i];
|
||||
}
|
||||
return fixedKey;
|
||||
}
|
||||
|
||||
static Uint8List _padData(Uint8List data) {
|
||||
final padLength = 4 - (data.length % 4);
|
||||
final paddedData = Uint8List(data.length + padLength);
|
||||
paddedData.setAll(0, data);
|
||||
return paddedData;
|
||||
}
|
||||
|
||||
static Uint8List _unpadData(Uint8List data) {
|
||||
int unpaddedLength = data.length;
|
||||
while (unpaddedLength > 0 && data[unpaddedLength - 1] == 0) {
|
||||
unpaddedLength--;
|
||||
}
|
||||
return Uint8List.sublistView(data, 0, unpaddedLength);
|
||||
}
|
||||
|
||||
static Uint8List _xxteaEncrypt(Uint8List data, Uint8List key) {
|
||||
final n = data.length ~/ 4;
|
||||
final v = Uint32List.view(data.buffer);
|
||||
final k = Uint32List.view(key.buffer);
|
||||
int sum = 0;
|
||||
const delta = 0x9E3779B9;
|
||||
|
||||
for (int i = 0; i < 6 + 52 ~/ n; i++) {
|
||||
sum = (sum + delta) & 0xFFFFFFFF;
|
||||
final e = (sum >> 2) & 3;
|
||||
for (int p = 0; p < n - 1; p++) {
|
||||
v[p] = (v[p] + _mx(sum, v, k, p, e, n)) & 0xFFFFFFFF;
|
||||
}
|
||||
v[n - 1] = (v[n - 1] + _mx(sum, v, k, n - 1, e, n)) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return Uint8List.view(v.buffer);
|
||||
}
|
||||
|
||||
static Uint8List _xxteaDecrypt(Uint8List data, Uint8List key) {
|
||||
final n = data.length ~/ 4;
|
||||
final v = Uint32List.view(data.buffer);
|
||||
final k = Uint32List.view(key.buffer);
|
||||
const delta = 0x9E3779B9;
|
||||
int sum = (6 + 52 ~/ n) * delta;
|
||||
|
||||
while (sum != 0) {
|
||||
final e = (sum >> 2) & 3;
|
||||
for (int p = n - 1; p > 0; p--) {
|
||||
v[p] = (v[p] - _mx(sum, v, k, p, e, n)) & 0xFFFFFFFF;
|
||||
}
|
||||
v[0] = (v[0] - _mx(sum, v, k, 0, e, n)) & 0xFFFFFFFF;
|
||||
sum = (sum - delta) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return Uint8List.view(v.buffer);
|
||||
}
|
||||
|
||||
static int _mx(int sum, Uint32List v, Uint32List k, int p, int e, int n) {
|
||||
return ((v[(p + 1) % n] ^ v[p]) + (k[p & 3 ^ e] ^ sum)) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static bool _constantTimeEquals(Uint8List a, Uint8List b) {
|
||||
if (a.length != b.length) return false;
|
||||
int result = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
result |= a[i] ^ b[i];
|
||||
}
|
||||
return result == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
//
|
||||
// void main() async {
|
||||
// final password = 'securePassword';
|
||||
// final secure = await XXTEA.fromPassword(password);
|
||||
//
|
||||
// final plaintext = 'Hello, secure world!';
|
||||
// final encrypted = secure.encryptString(plaintext);
|
||||
// print('Encrypted: \$encrypted');
|
||||
//
|
||||
// final decrypted = secure.decryptString(encrypted);
|
||||
// print('Decrypted: \$decrypted');
|
||||
//
|
||||
// final signature = secure.signString(plaintext);
|
||||
// print('Signature: \$signature');
|
||||
//
|
||||
// final isValid = secure.verifyStringSignature(plaintext, signature);
|
||||
// print('Signature valid: \$isValid');
|
||||
// }
|
|
@ -4,8 +4,7 @@ import 'dart:io';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:libac_dart/encryption/aes.dart';
|
||||
import 'package:libac_dart/encryption/rsa.dart';
|
||||
import 'package:libac_dart/encryption/xxtea.dart';
|
||||
import 'package:libac_dart/encryption/xtea.dart';
|
||||
|
||||
import '../nbt/NbtIo.dart';
|
||||
import '../nbt/Stream.dart';
|
||||
|
@ -14,9 +13,8 @@ import '../nbt/impl/CompoundTag.dart';
|
|||
import '../nbt/impl/StringTag.dart';
|
||||
|
||||
enum EncryptionType {
|
||||
RSA(value: 3),
|
||||
AES(value: 2),
|
||||
XXTEA(value: 1),
|
||||
XTEA(value: 1),
|
||||
NONE(value: 0);
|
||||
|
||||
final int value;
|
||||
|
@ -26,16 +24,12 @@ enum EncryptionType {
|
|||
switch (val) {
|
||||
case 1:
|
||||
{
|
||||
return EncryptionType.XXTEA;
|
||||
return EncryptionType.XTEA;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
return EncryptionType.AES;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
return EncryptionType.RSA;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return EncryptionType.NONE;
|
||||
|
@ -49,8 +43,6 @@ class PacketServer {
|
|||
static bool shouldRestart = true;
|
||||
static EncryptionType encryptionType = EncryptionType.NONE;
|
||||
static Uint8List AESKey = Uint8List(0);
|
||||
static RSAPrivateKey rsaPrivateKey = RSAPrivateKey(BigInt.zero, BigInt.zero);
|
||||
static RSAPublicKey rsaPublicKey = RSAPublicKey(BigInt.zero, BigInt.zero);
|
||||
static String PSK = "";
|
||||
static String TEA_SALT = "Harbinger 01/05/2025 @ 03:59:17 AM";
|
||||
|
||||
|
@ -115,16 +107,17 @@ class PacketServer {
|
|||
|
||||
List<int> remainingBytes = layer.readBytes(numBytes);
|
||||
if (ENCType == EncryptionType.AES) {
|
||||
AES aes = await AES.useKey(AESKey);
|
||||
remainingBytes = aes.decrypt(Uint8List.fromList(remainingBytes));
|
||||
} else if (ENCType == EncryptionType.RSA) {
|
||||
RSA rsa = await RSA.fromKeyPair(rsaPrivateKey, rsaPublicKey);
|
||||
remainingBytes = rsa.decrypt(Uint8List.fromList(remainingBytes));
|
||||
} else if (ENCType == EncryptionType.XXTEA) {
|
||||
XXTEA xtea = await XXTEA.fromPassword(PSK, salt: TEA_SALT);
|
||||
int ivLen = layer.readInt();
|
||||
List<int> ivBytes = layer.readBytes(ivLen);
|
||||
AESData encData = AESData(iv: ivBytes, data: remainingBytes);
|
||||
|
||||
AESCipher aes = await AESCipher.useKey(AESKey);
|
||||
remainingBytes = await aes.decrypt(encData);
|
||||
} else if (ENCType == EncryptionType.XTEA) {
|
||||
XTEA xtea = await XTEA(PSK);
|
||||
|
||||
remainingBytes =
|
||||
xtea.decryptBytes(Uint8List.fromList(remainingBytes));
|
||||
xtea.decipher(Uint8List.fromList(remainingBytes));
|
||||
}
|
||||
|
||||
CompoundTag tag =
|
||||
|
@ -153,14 +146,15 @@ class PacketServer {
|
|||
|
||||
// Encryption Subroutine
|
||||
if (ENCType == EncryptionType.AES) {
|
||||
AES aes = AES.useKey(AESKey);
|
||||
nbtData = aes.encrypt(nbtData);
|
||||
} else if (ENCType == EncryptionType.RSA) {
|
||||
RSA rsa = RSA.fromKeyPair(rsaPrivateKey, rsaPublicKey);
|
||||
nbtData = rsa.encrypt(nbtData);
|
||||
} else if (ENCType == EncryptionType.XXTEA) {
|
||||
XXTEA tea = await XXTEA.fromPassword(PSK, salt: TEA_SALT);
|
||||
nbtData = tea.encryptBytes(nbtData);
|
||||
AESCipher aes = AESCipher.useKey(AESKey);
|
||||
var encData = await aes.encrypt(nbtData);
|
||||
nbtData = Uint8List.fromList(encData.data);
|
||||
|
||||
layer.writeInt(encData.iv.length);
|
||||
layer.writeBytes(encData.iv);
|
||||
} else if (ENCType == EncryptionType.XTEA) {
|
||||
XTEA tea = await XTEA(PSK);
|
||||
nbtData = Uint8List.fromList(tea.encipher(nbtData));
|
||||
}
|
||||
|
||||
layer.writeLong(nbtData.lengthInBytes);
|
||||
|
|
|
@ -8,6 +8,10 @@ class Hashing {
|
|||
return bytes2Hash(md5SumStr(input));
|
||||
}
|
||||
|
||||
static String llMD5String(String src, int nonce) {
|
||||
return md5Hash("${src}:${nonce}");
|
||||
}
|
||||
|
||||
/// This will generate the Sha1 bytes and hash it using #bytes2Hash
|
||||
static String sha1Hash(String input) {
|
||||
return bytes2Hash(sha1SumStr(input));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: libac_dart
|
||||
description: "Aria's Creations code library"
|
||||
version: 1.3.010525+0414
|
||||
version: 1.3.010625+0228
|
||||
homepage: "https://zontreck.com"
|
||||
|
||||
environment:
|
||||
|
@ -10,6 +10,7 @@ environment:
|
|||
dependencies:
|
||||
crypto: ^3.0.3
|
||||
dio: ^5.5.0+1
|
||||
encrypt: ^5.0.3
|
||||
# path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
|
|
43
test/encryption_test.dart
Normal file
43
test/encryption_test.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:libac_dart/encryption/aes.dart';
|
||||
import 'package:libac_dart/encryption/xtea.dart';
|
||||
import 'package:libac_dart/utils/Hashing.dart';
|
||||
import 'package:test/expect.dart';
|
||||
import 'package:test/scaffolding.dart';
|
||||
|
||||
void main() {
|
||||
test("Test XTEA Encryption", () async {
|
||||
String knownEncryptedValue =
|
||||
"MU1T+AuHyBmALhbMOgZJQa5A"; // "Hello World!" // Test Key
|
||||
String keyHash = "131515d94e2574cd680ab1a41ecdc34c";
|
||||
List<int> knownKey = [320148953, 1311077581, 1745531300, 516801356];
|
||||
|
||||
XTEA tea = await XTEA("Test Key");
|
||||
expect(-1, tea.testKey(knownKey));
|
||||
|
||||
String newValue = tea.encryptString("Hello World!");
|
||||
|
||||
expect(Hashing.llMD5String("Test Key", 0), keyHash);
|
||||
expect(newValue, knownEncryptedValue);
|
||||
expect(tea.decryptString(newValue), "Hello World!");
|
||||
});
|
||||
|
||||
test("Test AES Implementation", () async {
|
||||
File key = File("test/aesKey.bin");
|
||||
File enc = File("test/HelloWorld.enc");
|
||||
File hw = File("test/HelloWorld.txt");
|
||||
String helloWorld = "Hello World!";
|
||||
|
||||
hw.writeAsStringSync(helloWorld);
|
||||
|
||||
AESCipher aes = await AESCipher.generate();
|
||||
AESData encryptedNew = await aes.encrypt(utf8.encode(helloWorld));
|
||||
|
||||
enc.writeAsBytes(encryptedNew.data);
|
||||
key.writeAsBytes(aes.getKey());
|
||||
|
||||
expect(helloWorld, utf8.decode(await aes.decrypt(encryptedNew)));
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue