import 'dart:typed_data'; import 'dart:math'; import 'package:pointycastle/export.dart'; class EncryptedVideoPayload { final Uint8List encryptedFileBytes; final String contentId; final String contentKeyHex; final String encryptedFileName; EncryptedVideoPayload({ required this.encryptedFileBytes, required this.contentId, required this.contentKeyHex, required this.encryptedFileName, }); } Future encryptVideoForUpload( Uint8List sourceBytes, ) async { final random = Random.secure(); final keyBytes = Uint8List.fromList( List.generate(16, (_) => random.nextInt(256)), ); final nonceBytes = Uint8List.fromList( List.generate(8, (_) => random.nextInt(256)), ); final contentId = _generateUuidV4(random); final contentIdBytes = _uuidToBytes(contentId); final contentKeyHex = _bytesToHex(keyBytes); final counterBlock = Uint8List(16); counterBlock.setRange(0, nonceBytes.length, nonceBytes); final cipher = CTRStreamCipher(AESEngine()) ..init( true, ParametersWithIV(KeyParameter(keyBytes), counterBlock), ); final encryptedData = cipher.process(sourceBytes); final magic = Uint8List.fromList('MYPLR1'.codeUnits); const version = 1; final headerSize = magic.length + 1 + contentIdBytes.length + nonceBytes.length; final finalBytes = Uint8List(headerSize + encryptedData.length); var offset = 0; finalBytes.setRange(offset, offset + magic.length, magic); offset += magic.length; finalBytes[offset] = version; offset += 1; finalBytes.setRange(offset, offset + contentIdBytes.length, contentIdBytes); offset += contentIdBytes.length; finalBytes.setRange(offset, offset + nonceBytes.length, nonceBytes); offset += nonceBytes.length; finalBytes.setRange(offset, offset + encryptedData.length, encryptedData); return EncryptedVideoPayload( encryptedFileBytes: finalBytes, contentId: contentId, contentKeyHex: contentKeyHex, encryptedFileName: '$contentId.spot', ); } String _bytesToHex(Uint8List bytes) { final buffer = StringBuffer(); for (final byte in bytes) { buffer.write(byte.toRadixString(16).padLeft(2, '0')); } return buffer.toString(); } Uint8List _uuidToBytes(String uuid) { final hex = uuid.replaceAll('-', ''); final output = Uint8List(16); for (var i = 0; i < 16; i++) { output[i] = int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16); } return output; } String _generateUuidV4(Random random) { final bytes = List.generate(16, (_) => random.nextInt(256)); bytes[6] = (bytes[6] & 0x0f) | 0x40; bytes[8] = (bytes[8] & 0x3f) | 0x80; final hex = bytes .map((b) => b.toRadixString(16).padLeft(2, '0')) .join(); return '${hex.substring(0, 8)}-' '${hex.substring(8, 12)}-' '${hex.substring(12, 16)}-' '${hex.substring(16, 20)}-' '${hex.substring(20, 32)}'; }