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
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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue