156 lines
4.7 KiB
Dart
156 lines
4.7 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
import 'dart:math';
|
|
|
|
class SkyEncrypt {
|
|
static const int bfSize = 2048;
|
|
static const String enStrTag = r'$';
|
|
|
|
// Generates a random salt of size between 16 and 64 bytes
|
|
static Uint8List randSalt() {
|
|
final rand = Random.secure();
|
|
final size = rand.nextInt(49) + 16; // 16..64
|
|
return Uint8List.fromList(List.generate(size, (_) => rand.nextInt(256)));
|
|
}
|
|
|
|
// Encrypts the given data with a random salt
|
|
static Uint8List en(Uint8List data) {
|
|
if (data.isEmpty) return data;
|
|
final salt = randSalt();
|
|
final encryptedData = enWithSalt(data, salt);
|
|
return Uint8List.fromList([salt.length, ...salt, ...encryptedData]);
|
|
}
|
|
|
|
// Decrypts the given encrypted data
|
|
static Uint8List de(Uint8List data) {
|
|
if (data.isEmpty) return data;
|
|
final saltLen = data[0];
|
|
final salt = data.sublist(1, 1 + saltLen);
|
|
final encrypted = data.sublist(1 + saltLen);
|
|
return deWithSalt(encrypted, salt);
|
|
}
|
|
|
|
// Encrypts data with a specified salt
|
|
static Uint8List enWithSalt(Uint8List data, Uint8List salt) {
|
|
final mixedData = mixSalt(data, salt);
|
|
return cxEd(mixedData);
|
|
}
|
|
|
|
// Decrypts data with a specified salt
|
|
static Uint8List deWithSalt(Uint8List data, Uint8List salt) {
|
|
final decryptedData = cxEd(data);
|
|
return removeSalt(decryptedData, salt);
|
|
}
|
|
|
|
// Simple XOR-based encryption/decryption (bitwise negation)
|
|
static Uint8List cxEd(Uint8List data) {
|
|
return Uint8List.fromList(data.map((b) => b ^ 0xFF).toList());
|
|
}
|
|
|
|
// Apply salt to the data for encryption
|
|
static Uint8List mixSalt(Uint8List data, Uint8List salt) {
|
|
if (salt.isEmpty) return data;
|
|
return Uint8List.fromList(
|
|
List.generate(data.length, (i) {
|
|
final s = salt[i % salt.length];
|
|
return calSalt(data[i], s);
|
|
}),
|
|
);
|
|
}
|
|
|
|
// Remove salt from the data after decryption
|
|
static Uint8List removeSalt(Uint8List data, Uint8List salt) {
|
|
if (salt.isEmpty) return data;
|
|
return Uint8List.fromList(
|
|
List.generate(data.length, (i) {
|
|
final s = salt[i % salt.length];
|
|
return calRemoveSalt(data[i], s);
|
|
}),
|
|
);
|
|
}
|
|
|
|
// Calculate a modified value after mixing salt (for encryption)
|
|
static int calSalt(int v, int s) {
|
|
final r = v ^ 0xFF;
|
|
return s > r ? (s - r - 1) & 0xFF : (v + s) & 0xFF;
|
|
}
|
|
|
|
// Reverse the salt mixing process for decryption
|
|
static int calRemoveSalt(int v, int s) {
|
|
return v >= s ? (v - s) & 0xFF : (0xFF - (s - v) + 1) & 0xFF;
|
|
}
|
|
|
|
// Encrypt a string and return the hex representation
|
|
static String cxEStr(String data) {
|
|
return cxEStrAsBytes(
|
|
data,
|
|
).map((b) => b.toRadixString(16).padLeft(2, '0')).join();
|
|
}
|
|
|
|
// Encrypt string and return as bytes
|
|
static Uint8List cxEStrAsBytes(String data) {
|
|
return cxEd(Uint8List.fromList(utf8.encode(data)));
|
|
}
|
|
|
|
// Decrypt a hex string to a regular string
|
|
static String cxDStr(String data) {
|
|
final bytes = Uint8List.fromList([
|
|
for (int i = 0; i < data.length; i += 2)
|
|
int.parse(data.substring(i, i + 2), radix: 16),
|
|
]);
|
|
return utf8.decode(cxEd(bytes));
|
|
}
|
|
|
|
// Encrypt string data and return in the form of hex string with prefix
|
|
static String enStr(String data) {
|
|
return enBytesStr(Uint8List.fromList(utf8.encode(data)));
|
|
}
|
|
|
|
// Encrypt bytes and return as hex string with prefix
|
|
static String enBytesStr(Uint8List data) {
|
|
final encrypted = en(data);
|
|
return '$enStrTag${encrypted.map((b) => b.toRadixString(16).padLeft(2, '0')).join()}';
|
|
}
|
|
|
|
// Decrypt a string with encoded prefix (e.g., "$" symbol)
|
|
static String deStr(String data) {
|
|
return utf8.decode(deStrBytes(data));
|
|
}
|
|
|
|
// Decrypt the byte array extracted from a string
|
|
static Uint8List deStrBytes(String data) {
|
|
if (!data.startsWith(enStrTag)) {
|
|
throw ArgumentError("Invalid encoded string");
|
|
}
|
|
final hexData = data.substring(1);
|
|
final bytes = Uint8List.fromList([
|
|
for (int i = 0; i < hexData.length; i += 2)
|
|
int.parse(hexData.substring(i, i + 2), radix: 16),
|
|
]);
|
|
return de(bytes);
|
|
}
|
|
|
|
// Copy encrypted data from a stream to another stream
|
|
static Future<int> copy(
|
|
Stream<List<int>> reader,
|
|
StreamSink<List<int>> writer,
|
|
) async {
|
|
int total = 0;
|
|
await for (final chunk in reader) {
|
|
total += chunk.length;
|
|
final encrypted = chunk.map((b) => b ^ 0xFF).toList();
|
|
writer.add(encrypted);
|
|
}
|
|
await writer.close();
|
|
return total;
|
|
}
|
|
|
|
// Custom encryption with condition (even and odd byte values handled differently)
|
|
static Uint8List cxEd1(Uint8List data) {
|
|
return Uint8List.fromList(
|
|
data.map((b) => (b % 2 == 1) ? (b ^ 0xFF) : b).toList(),
|
|
);
|
|
}
|
|
}
|