├── analysis_options.yaml ├── lib ├── utils │ ├── iterable.dart │ ├── listops.dart │ ├── big_int.dart │ └── ufixnum.dart ├── asymmetric │ └── rsa │ │ ├── signer │ │ ├── README.md │ │ ├── signer.dart │ │ ├── rsassa_pks1_v15.dart │ │ └── emsa_pss.dart │ │ ├── README.md │ │ ├── encoder │ │ ├── emsa_pss.dart │ │ └── emsaPkcs1v15.dart │ │ ├── engine │ │ ├── encrypter.dart │ │ └── decrypter.dart │ │ └── rsa.dart ├── ninja.dart ├── block_cipher │ ├── block_cipher.dart │ └── modes │ │ ├── cbc.dart │ │ └── ctr.dart ├── hash │ ├── hash.dart │ └── ripemd160.dart ├── padder │ ├── padder.dart │ ├── mgf │ │ └── mgf.dart │ ├── pkcs7.dart │ ├── emePkcs1v15.dart │ └── eme_oaep.dart └── symmetric │ └── aes │ ├── aes.dart │ └── engine.dart ├── example ├── rsa │ ├── keygen_example.dart │ ├── rsa_pkcs1v15_encryption.dart │ ├── rsa_oaep_encryption.dart │ ├── rsa_pkcs11v15_signature_example.dart │ ├── pss_signature.dart │ ├── rsa_example.dart │ └── pem_example.dart ├── aes_example.dart ├── hash │ └── ripemd160.dart ├── aes128 │ ├── aes_128_cbc.dart │ └── aes_128_ctr.dart └── example.dart ├── .gitignore ├── test ├── rsa │ ├── encoder │ │ └── emsa_pcks1v15.dart │ ├── signer │ │ ├── rsa_pkcs1v15_test.dart │ │ └── rsa_pss_test.dart │ ├── encryption │ │ ├── raw_test.dart │ │ ├── oaep_test.dart │ │ └── pkcs1v15_test.dart │ └── pem_test.dart ├── padder │ ├── mgf1_test.dart │ └── emePkcs1v1dot5_test.dart ├── utils │ └── bigint_test.dart ├── aes │ ├── aes_test.dart │ └── aes_cbc_test.dart ├── hash │ └── ripemd160 │ │ └── ripemd160_test.dart └── rsa_test.dart ├── pubspec.yaml ├── CHANGELOG.md ├── LICENSE ├── README.md └── LICENSES └── pointy_castles.LICENSE /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.1.8.0.yaml 2 | 3 | analyzer: 4 | -------------------------------------------------------------------------------- /lib/utils/iterable.dart: -------------------------------------------------------------------------------- 1 | import 'package:collection/collection.dart'; 2 | 3 | const iterableEquality = IterableEquality(); 4 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/signer/README.md: -------------------------------------------------------------------------------- 1 | > TODO 2 | 3 | # References 4 | 5 | + [RSA sign and verify using openssl behind the scene](https://medium.com/@bn121rajesh/rsa-sign-and-verify-using-openssl-behind-the-scene-bf3cac0aade2) -------------------------------------------------------------------------------- /example/rsa/keygen_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 2 | 3 | void main() { 4 | final privateKey = RSAPrivateKey.generate(1024); 5 | print(privateKey.p); 6 | print(privateKey.q); 7 | print(privateKey.n.bitLength); 8 | } 9 | -------------------------------------------------------------------------------- /lib/ninja.dart: -------------------------------------------------------------------------------- 1 | library ninja; 2 | 3 | export 'asymmetric/rsa/rsa.dart'; 4 | export 'padder/padder.dart'; 5 | export 'symmetric/aes/aes.dart'; 6 | export 'block_cipher/block_cipher.dart'; 7 | 8 | export 'utils/big_int.dart'; 9 | export 'hash/hash.dart'; 10 | -------------------------------------------------------------------------------- /lib/block_cipher/block_cipher.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | export 'modes/cbc.dart'; 4 | export 'modes/ctr.dart'; 5 | 6 | abstract class BlockCipher { 7 | int get blockSize; 8 | 9 | int processBlock(ByteData input, ByteData output); 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | .pub/ 5 | build/ 6 | # Remove the following pattern if you wish to check in your lock file 7 | pubspec.lock 8 | 9 | # Directory created by dartdoc 10 | doc/api/ 11 | 12 | *.iml 13 | .idea 14 | 15 | example/scratch.dart -------------------------------------------------------------------------------- /example/aes_example.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'package:ninja/ninja.dart'; 3 | 4 | main() { 5 | final aes = AESKey(Uint8List.fromList(List.generate(16, (i) => i))); 6 | String encoded = aes.encryptToBase64('Dart'); 7 | print(encoded); 8 | String decoded = aes.decryptToUtf8(encoded); 9 | print(decoded); 10 | } 11 | -------------------------------------------------------------------------------- /test/rsa/encoder/emsa_pcks1v15.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/asymmetric/rsa/encoder/emsaPkcs1v15.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('EMSA-PKCS1-V1_5-ENCODE', () { 8 | test('', () { 9 | final out = emsaPkcs1v15Encode( 10 | utf8.encode("hello world!"), 256, EmsaHasher.sha256); 11 | print(out); 12 | }); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /example/hash/ripemd160.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/hash/hash.dart'; 2 | 3 | void perform(String msg) { 4 | var hash = ripemd160.convert(msg.codeUnits).asHex; 5 | print(hash); 6 | } 7 | 8 | void main() { 9 | // perform('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890^_'); 10 | perform( 11 | '''ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890^_abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq()+?#'"!'''); 12 | } 13 | -------------------------------------------------------------------------------- /test/padder/mgf1_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/padder/mgf/mgf.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | void main() { 7 | group('MGF1', () { 8 | test('encode', () { 9 | print(mgf1Sha1.encode(10, utf8.encode('hello world!'))); 10 | print(mgf1Sha1.encode(20, utf8.encode('hello world!'))); 11 | print(mgf1Sha1.encode(100, utf8.encode('hello world!'))); 12 | print(mgf1Sha1.encode(64, utf8.encode('hello world!'))); 13 | }); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/signer/signer.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 2 | 3 | export 'emsa_pss.dart'; 4 | export 'rsassa_pks1_v15.dart'; 5 | 6 | abstract class RsaSigner { 7 | List sign(RSAPrivateKey key, /* String | List | BigInt */ msg); 8 | 9 | String signToBase64(RSAPrivateKey key, /* String | List | BigInt */ msg); 10 | } 11 | 12 | abstract class RsaVerifier { 13 | bool verify( 14 | RSAPublicKey key, 15 | /* String | List | BigInt */ signature, 16 | /* String | List | BigInt */ msg); 17 | } 18 | -------------------------------------------------------------------------------- /test/utils/bigint_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/utils/big_int.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('bigint', () { 6 | test('base64ToBigInt', () { 7 | expect(base64ToBigInt('AQAB').toString(), '65537'); 8 | expect( 9 | base64ToBigInt( 10 | '2wWNDbYbfq/yMaFw60Kda2S6qoj2ZY6rkjobLg0FvjpyHb6Bcvz+wLftfYEYBKe3ZjKYCbvHBLb5ATz1hi8N0Q==') 11 | .toString(), 12 | '11471096350072129820579819100426547181616187185658504704996065334930805271197099322753245009150228584617512330162571541229290378786994493391408050685808081'); 13 | }); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /example/aes128/aes_128_cbc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:ninja/ninja.dart'; 6 | 7 | 8 | void main() { 9 | // echo -n 'Dart' | openssl enc -aes-128-ctr -K 000102030405060708090a0b0c0d0e0f -iv 3ffabe88d6a25a9f4ce3141a1e388ab6 10 | final iv = CTRBlockCipherMode.makeRandomIV(random: Random(12345)); 11 | final key = Uint8List.fromList(List.generate(16, (i) => i)); 12 | print(key.toHex()); 13 | print(iv.toHex()); 14 | final aes = AESKey(key); 15 | String encoded = aes.encryptCbcToBase64('Dart', iv: iv); 16 | print(encoded); 17 | print(base64Decode(encoded).toHex()); 18 | String decoded = aes.decryptCbcToUtf8(encoded, iv: iv); 19 | print(decoded); 20 | } -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ninja 2 | description: Cryptography dart library to encrypt, decrypt, sign and verify messages 3 | version: 3.0.8 4 | homepage: https://github.com/ninja-dart/ninja 5 | 6 | documentation: 7 | 8 | environment: 9 | sdk: '>=2.15.0 <3.0.0' 10 | 11 | dependencies: 12 | crypto: ^3.0.1 13 | ninja_prime: ^2.0.0 14 | ninja_pem: ^2.0.0 15 | ninja_asn1: ^2.0.0 16 | ninja_hex: ^2.0.1 17 | collection: ^1.15.0 18 | 19 | dev_dependencies: 20 | test: ^1.17.10 21 | pedantic: ^1.11.1 22 | ninja_openssl: ^1.0.4 23 | 24 | false_secrets: 25 | - /README.md 26 | - /example/rsa/pem_example.dart 27 | - /example/rsa/pss_signature.dart 28 | - /example/rsa/rsa_oaep_encryption.dart 29 | - /example/rsa/rsa_pkcs11v15_signature_example.dart 30 | - /example/rsa/rsa_pkcs1v15_encryption.dart 31 | - /test/rsa/pem_test.dart -------------------------------------------------------------------------------- /example/aes128/aes_128_ctr.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:ninja/ninja.dart'; 6 | 7 | 8 | void main() { 9 | // echo -n 'Dart' | openssl enc -aes-128-ctr -e -a -K 000102030405060708090a0b0c0d0e0f -iv 3ffabe88d6a25a9f4ce3141a1e388ab6 -p -nopad -nosalt 10 | // echo -n 'u0uz7g==' | base64 -d | openssl enc -aes-128-ctr -d -K 000102030405060708090a0b0c0d0e0f -iv 3ffabe88d6a25a9f4ce3141a1e388ab6 -nopad -nosalt 11 | final iv = CTRBlockCipherMode.makeRandomIV(random: Random(12345)); 12 | final key = Uint8List.fromList(List.generate(16, (i) => i)); 13 | print(key.toHex()); 14 | print(iv.toHex()); 15 | final aes = AESKey(key); 16 | String encoded = aes.encryptCtrToBase64('erqwerqwrqwerqwerqwerwqerqwerqwerqwerqwerqwerqwr', iv: iv); 17 | print(encoded); 18 | print(base64Decode(encoded).toHex()); 19 | String decoded = aes.decryptCtrToUtf8(encoded, iv: iv); 20 | print(decoded); 21 | } -------------------------------------------------------------------------------- /lib/utils/listops.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | abstract class ListOps { 4 | static Uint8List xor(Iterable a, Iterable b) { 5 | if (a.length != b.length) { 6 | throw Exception('Lengths of a and b do not match'); 7 | } 8 | 9 | final ret = Uint8List(a.length); 10 | 11 | final aIter = a.iterator; 12 | final bIter = b.iterator; 13 | for (int i = 0; i < ret.length; i++) { 14 | aIter.moveNext(); 15 | bIter.moveNext(); 16 | ret[i] = aIter.current ^ bIter.current; 17 | } 18 | 19 | return ret; 20 | } 21 | 22 | static void xorToByteData(ByteData a, Iterable b) { 23 | if (a.lengthInBytes != b.length) { 24 | throw Exception('Lengths of a and b do not match'); 25 | } 26 | 27 | int length = a.lengthInBytes; 28 | 29 | final bIter = b.iterator; 30 | for (int i = 0; i < length; i++) { 31 | bIter.moveNext(); 32 | a.setUint8(i, a.getUint8(i) ^ bIter.current); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/hash/hash.dart: -------------------------------------------------------------------------------- 1 | export 'ripemd160.dart'; 2 | 3 | import 'package:crypto/crypto.dart'; 4 | import 'package:ninja/ninja.dart'; 5 | 6 | extension DigestExt on Digest { 7 | String get asHex => bigIntToHex(asBigInt); 8 | 9 | BigInt get asBigInt => bytes.asBigInt(); 10 | } 11 | 12 | /// A sink used to get a digest value out of `Hash.startChunkedConversion`. 13 | class DigestSink extends Sink { 14 | /// The value added to the sink. 15 | /// 16 | /// A value must have been added using [add] before reading the `value`. 17 | Digest get value => _value!; 18 | 19 | Digest? _value; 20 | 21 | /// Adds [value] to the sink. 22 | /// 23 | /// Unlike most sinks, this may only be called once. 24 | @override 25 | void add(Digest value) { 26 | if (_value != null) throw StateError('add may only be called once.'); 27 | _value = value; 28 | } 29 | 30 | @override 31 | void close() { 32 | if (_value == null) throw StateError('add must be called once.'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /example/rsa/rsa_pkcs1v15_encryption.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | 3 | main() { 4 | final privateKeyPem = ''' 5 | -----BEGIN RSA PRIVATE KEY----- 6 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 7 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 8 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 9 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 10 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 11 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 12 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 13 | -----END RSA PRIVATE KEY-----'''; 14 | 15 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 16 | final publicKey = privateKey.toPublicKey; 17 | 18 | String encrypted = publicKey.encryptToBase64( 19 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 20 | print(encrypted); 21 | String decrypted = privateKey.decryptToUtf8(encrypted); 22 | print(decrypted); 23 | } 24 | -------------------------------------------------------------------------------- /example/rsa/rsa_oaep_encryption.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | 3 | void main() { 4 | final privateKeyPem = ''' 5 | -----BEGIN RSA PRIVATE KEY----- 6 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 7 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 8 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 9 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 10 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 11 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 12 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 13 | -----END RSA PRIVATE KEY-----'''; 14 | 15 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 16 | final publicKey = privateKey.toPublicKey; 17 | 18 | String encrypted = publicKey.encryptOaepToBase64( 19 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 20 | print(encrypted); 21 | String decrypted = privateKey.decryptOaepToUtf8(encrypted); 22 | print(decrypted); 23 | } 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.0.8 2 | 3 | + CTR block mode support 4 | 5 | ## 3.0.7 6 | 7 | + Uint8ListBigInt.toHex is endian aware 8 | 9 | ## 3.0.6 10 | 11 | + Little endian support for byte to BigInt conversion. 12 | 13 | Breaking change: 14 | 15 | + Uint8ListBigInt.asBigInt is converted from getter to method 16 | 17 | ## 3.0.5 18 | 19 | + Added `DigestSink` 20 | 21 | ## 3.0.4 22 | 23 | Breaking changes 24 | 25 | + Changed toHex from getter to function. Now it 26 | allows requesting for fixed length hex string. 27 | 28 | ## 3.0.3 29 | 30 | + RIPEMD160 hash 31 | 32 | ## 3.0.2 33 | 34 | + Null safety 35 | 36 | ## 3.0.1 37 | 38 | + Fixed typo bug for default oaepPadder for RSAPublicKey.encryptOaep method 39 | 40 | ## 3.0.0 41 | 42 | + Simpler and elegant API 43 | + OAEP encryption 44 | + PKCS1V15 encryption 45 | + RSASSA-PSS sign 46 | + RSASSA-PKCS1-V1_5 sign 47 | 48 | ## 2.0.1 49 | 50 | + Pub publish fixes 51 | 52 | ## 2.0.0 53 | 54 | + Port to Dart 2.0.0 55 | 56 | ## 1.0.0 57 | 58 | + Architecture 59 | + Added 60 | + `AES` 61 | + `RSA` 62 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/README.md: -------------------------------------------------------------------------------- 1 | # Generation 2 | 3 | ## Generate private key 4 | 5 | ```bash 6 | openssl genrsa -out priv.pem 1024 7 | ``` 8 | 9 | ## Extract public key 10 | 11 | ```bash 12 | openssl rsa -in priv.pem -out pub.pem -pubout -outform PEM 13 | ``` 14 | 15 | ## Dump modulus 16 | 17 | ```bash 18 | openssl rsa -in pub.pem -pubin -modulus 19 | openssl rsa -in priv.pem -modulus 20 | ``` 21 | 22 | ### Hex to int 23 | 24 | ```bash 25 | echo 'ibase=16;F3B24371577F76061B9F6D25720B7C21A4EEF55CE1DFDFF0D63F251F34A1B571AEC4855A9144529F14D5EE6D87AF8C0D9579708453644D6B93661CBF0F987CABDB6C1E0C3D8A274619044F51CCFB3FBA1D525FC373F596CB48EA6F8F8F56E22A3ABD3DABA79F816EFDBA2E10BFCC6F1D3797935FD16DA219791F4B5D8CD2FB2B' | bc 26 | ``` 27 | 28 | ## ASN1 dump 29 | 30 | ```bash 31 | openssl asn1parse -in priv.pem -i -dump 32 | ``` 33 | 34 | # PKCS Encryption/decryption 35 | 36 | ## Encryption 37 | 38 | ```bash 39 | openssl rsautl -inkey mypublic.pem -pubin -encrypt -pkcs -in hello.txt | hexdump -e '/1 "%02X"' 40 | ``` 41 | 42 | ## Decryption 43 | 44 | ```bash 45 | 46 | ``` -------------------------------------------------------------------------------- /example/rsa/rsa_pkcs11v15_signature_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 2 | import 'package:ninja/asymmetric/rsa/signer/emsa_pss.dart'; 3 | 4 | void main() { 5 | final privateKeyPem = ''' 6 | -----BEGIN RSA PRIVATE KEY----- 7 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 8 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 9 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 10 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 11 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 12 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 13 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 14 | -----END RSA PRIVATE KEY-----'''; 15 | 16 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 17 | final publicKey = privateKey.toPublicKey; 18 | 19 | final message = 'abcdefghijklmnopqrstuvwxyz\n'; 20 | 21 | final signature = privateKey.signSsaPkcs1v15ToBase64(message); 22 | print(signature); 23 | 24 | print(publicKey.verifySsaPkcs1v15(signature, message)); 25 | } 26 | -------------------------------------------------------------------------------- /lib/padder/padder.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | export 'eme_oaep.dart'; 4 | export 'emePkcs1v15.dart'; 5 | export 'pkcs7.dart'; 6 | 7 | abstract class Padder { 8 | Uint8List pad(int blockSize, Iterable input); 9 | 10 | Iterable unpad(int blockSize, Iterable input); 11 | } 12 | 13 | /// Can pad individual blocks separately 14 | abstract class IndividualBlockPadder { 15 | void padBlock(int blockSize, Iterable block, ByteData output); 16 | 17 | Iterable unpadBlock(int blockSize, Iterable block); 18 | } 19 | 20 | /// [Padder] that does not perform any padding. 21 | class NopPadder implements Padder { 22 | Uint8List pad(int blockSize, Iterable input) { 23 | if (input.length % blockSize != 0) { 24 | throw Exception('Input length must be multiple of blockSize: $blockSize'); 25 | } 26 | 27 | return Uint8List.fromList(input.toList()); 28 | } 29 | 30 | Iterable unpad(int blockSize, Iterable input) { 31 | if (input.length % blockSize != 0) { 32 | throw Exception('Input length must be multiple of blockSize: $blockSize'); 33 | } 34 | 35 | return input; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/rsa/pss_signature.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 2 | import 'package:ninja/asymmetric/rsa/signer/emsa_pss.dart'; 3 | 4 | void main() { 5 | final privateKeyPem = ''' 6 | -----BEGIN RSA PRIVATE KEY----- 7 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 8 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 9 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 10 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 11 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 12 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 13 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 14 | -----END RSA PRIVATE KEY-----'''; 15 | 16 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 17 | final publicKey = privateKey.toPublicKey; 18 | 19 | final message = 'abcdefghijklmnopqrstuvwxyz\n'; 20 | 21 | final signature = privateKey.signPssToBase64(message); 22 | print(signature); 23 | 24 | print(publicKey.verifySsaPss(signature, message)); 25 | 26 | final verifier = RsaSsaPssVerifier(saltLength: 10); 27 | print(verifier.extractSalt(publicKey, signature)); 28 | } 29 | -------------------------------------------------------------------------------- /lib/padder/mgf/mgf.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:crypto/crypto.dart' as crypto; 4 | import 'package:ninja/utils/big_int.dart'; 5 | 6 | abstract class Mgf { 7 | List encode(int blockSize, Iterable input); 8 | } 9 | 10 | class Mgf1 implements Mgf { 11 | final crypto.Hash hasher; 12 | 13 | Mgf1({crypto.Hash? hasher}) : hasher = hasher ?? crypto.sha1; 14 | 15 | Uint8List encode(int blockSize, Iterable input) { 16 | final inputLen = input.length; 17 | final output = Uint8List(blockSize); 18 | 19 | final inputBlock = Uint8List(inputLen + 4); 20 | inputBlock.setRange(0, inputLen, input); 21 | 22 | int i = 0; 23 | int offset = 0; 24 | while (offset < blockSize) { 25 | BigInt counter = BigInt.from(i); 26 | inputBlock.setRange( 27 | inputLen, inputLen + 4, bigIntToBytes(counter, outLen: 4)); 28 | 29 | final outputBlock = hasher.convert(inputBlock).bytes; 30 | int end = offset + outputBlock.length; 31 | if (end > blockSize) { 32 | end = blockSize; 33 | } 34 | output.setRange(offset, end, outputBlock); 35 | offset = end; 36 | 37 | i++; 38 | } 39 | 40 | return output; 41 | } 42 | } 43 | 44 | final mgf1Sha1 = Mgf1(hasher: crypto.sha1); 45 | 46 | final mgf1Sha256 = Mgf1(hasher: crypto.sha256); 47 | -------------------------------------------------------------------------------- /example/rsa/rsa_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | 3 | final privateKey = RSAPrivateKey.fromASN1( 4 | 'MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlkNmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAbYQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRkBuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAexIGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAww+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw=='); 5 | final publicKey = privateKey.toPublicKey; 6 | 7 | void short() { 8 | String encrypted = publicKey.encryptToBase64('hello world!'); 9 | print(encrypted); 10 | String decrypted = privateKey.decryptToUtf8(encrypted); 11 | print(decrypted); 12 | } 13 | 14 | void long() { 15 | String encrypted = publicKey.encryptToBase64( 16 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 17 | print(encrypted); 18 | String decrypted = privateKey.decryptToUtf8(encrypted); 19 | print(decrypted); 20 | } 21 | 22 | main() { 23 | print(privateKey); 24 | 25 | short(); 26 | 27 | long(); 28 | } 29 | -------------------------------------------------------------------------------- /lib/padder/pkcs7.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'padder.dart'; 4 | 5 | class PKCS7Padder implements Padder { 6 | const PKCS7Padder(); 7 | 8 | Uint8List pad(int blockSize, Iterable input) { 9 | if (blockSize > 255) { 10 | throw Exception('PKCS #7 only supports block sizes less than 256'); 11 | } 12 | 13 | int numBlocks = (input.length + blockSize) ~/ blockSize; 14 | int outSize = numBlocks * blockSize; 15 | 16 | final ret = Uint8List(outSize); 17 | 18 | ret.setAll(0, input); 19 | for (int i = input.length; i < outSize; i++) { 20 | ret[i] = outSize - input.length; 21 | } 22 | 23 | return ret; 24 | } 25 | 26 | Iterable unpad(int blockSize, Iterable data) { 27 | if (blockSize > 255) { 28 | throw Exception('PKCS #7 only supports block sizes less than 256'); 29 | } 30 | 31 | if (data.length % blockSize != 0) { 32 | throw ArgumentError('Data size must be multiple of $blockSize!'); 33 | } 34 | 35 | if (data.last > blockSize) { 36 | throw ArgumentError.value(data, 'data', 'Invalid PKCS7 padding!'); 37 | } 38 | 39 | final int pads = data.last; 40 | 41 | if (pads == blockSize) { 42 | if (data.length <= blockSize) { 43 | throw ArgumentError('Invalid PKCS7 padding!'); 44 | } 45 | } 46 | 47 | return data.take(data.length - pads); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/padder/emePkcs1v1dot5_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/ninja.dart'; 4 | import 'package:ninja/padder/emePkcs1v15.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('EME-PKCS1-V1_5', () { 9 | final padder = EmePkcs1v15Encoder(); 10 | 11 | test('shortmsg', () { 12 | final message = utf8.encode('hello world!'); 13 | // print('message: ${message.length} $message'); 14 | final padded = padder.pad(32, message); 15 | // print(hexCodec.encode(padded)); 16 | final unpadded = padder.unpad(32, padded).toList(); 17 | // print('message: ${unpadded.length} $unpadded'); 18 | expect(message, unpadded); 19 | }); 20 | 21 | test('longmsg', () { 22 | final message = utf8.encode( 23 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 24 | // print('message: ${message.length} $message'); 25 | final padded = padder.pad(32, message); 26 | // print(hexCodec.encode(padded)); 27 | final unpadded = padder.unpad(32, padded).toList(); 28 | // print('message: ${unpadded.length} $unpadded'); 29 | expect(message, unpadded); 30 | }); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/encoder/emsa_pss.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:crypto/crypto.dart'; 5 | import 'package:ninja/padder/mgf/mgf.dart'; 6 | import 'package:ninja/utils/listops.dart'; 7 | 8 | class EmsaPssEncoder { 9 | final Mgf mgf; 10 | 11 | final Hash hasher; 12 | 13 | final int saltLength; 14 | 15 | EmsaPssEncoder({Mgf? mgf, Hash? hasher, this.saltLength = 0}) 16 | : mgf = mgf ?? mgf1Sha1, 17 | hasher = hasher ?? sha1; 18 | 19 | Uint8List encode(int blockSize, List input) { 20 | final mHash = hasher.convert(input).bytes; 21 | 22 | if (blockSize < mHash.length + saltLength + 2) { 23 | throw Exception('encoding error. blockSize too small'); 24 | } 25 | 26 | Random random = Random.secure(); 27 | 28 | final salt = List.generate(saltLength, (index) => random.nextInt(256)); 29 | 30 | final mDash = [ 31 | ...List.filled(8, 0), 32 | ...mHash, 33 | ...salt, 34 | ]; 35 | 36 | final h = hasher.convert(mDash).bytes; 37 | 38 | final ps = List.filled(blockSize - saltLength - mHash.length - 2, 0); 39 | 40 | final db = [ 41 | ...ps, 42 | 0x01, 43 | ...salt, 44 | ]; 45 | 46 | final dbMask = mgf.encode(blockSize - mHash.length - 1, h); 47 | 48 | final maskedDb = ListOps.xor(db, dbMask); 49 | 50 | final em = Uint8List.fromList([ 51 | ...maskedDb, 52 | ...h, 53 | 0xbc, 54 | ]); 55 | 56 | return em; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Ravi Teja Gudapati. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /test/aes/aes_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('AES-128-ECB', () { 6 | final aesKey1 = AESKey.fromHex('B025700C28E7F0F97F7EA8EEEEC29F9F'); 7 | 8 | group('short_padded', () { 9 | test('Encoding', () { 10 | String value = aesKey1.encryptToBase64('hello world!\n'); 11 | expect(value, 'Sesg9NhOm+eKFe9hU/mfSA=='); 12 | }); 13 | 14 | test('Decode', () { 15 | final decoded = aesKey1.decryptToUtf8('Sesg9NhOm+eKFe9hU/mfSA=='); 16 | expect(decoded, 'hello world!\n'); 17 | }); 18 | }); 19 | 20 | group('short', () { 21 | test('Encoding', () { 22 | String value = aesKey1.encryptToBase64('hello world!!!!\n'); 23 | expect(value, 'PGxrnKUS/zhDneaO3c0APkKdSMS47iRQ8KLISthNtNU='); 24 | }); 25 | 26 | test('Decode', () { 27 | final decoded = aesKey1 28 | .decryptToUtf8('PGxrnKUS/zhDneaO3c0APkKdSMS47iRQ8KLISthNtNU='); 29 | expect(decoded, 'hello world!!!!\n'); 30 | }); 31 | }); 32 | 33 | group('long', () { 34 | test('Encoding', () { 35 | String value = aesKey1.encryptToBase64( 36 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit ........\n'); 37 | expect(value, 38 | 'MR2pq72G8HPSyM8CzTcWkq5771gkoBPU/4fSQQSKVJUGjnDw5jrmCDchRIsd2XrfiWsbYG63PjfIG+OOJuVuqHgivoT6O+DtU5/4femIJTo='); 39 | }); 40 | 41 | test('Decode', () { 42 | final decoded = aesKey1.decryptToUtf8( 43 | 'MR2pq72G8HPSyM8CzTcWkq5771gkoBPU/4fSQQSKVJUGjnDw5jrmCDchRIsd2XrfiWsbYG63PjfIG+OOJuVuqHgivoT6O+DtU5/4femIJTo='); 44 | expect(decoded, 45 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit ........\n'); 46 | }); 47 | }); 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /test/hash/ripemd160/ripemd160_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | import 'package:test/expect.dart'; 3 | import 'package:test/scaffolding.dart'; 4 | 5 | class TestCase { 6 | final Map hashes; 7 | 8 | TestCase(this.hashes); 9 | 10 | void perform() { 11 | for (final msg in hashes.keys) { 12 | final hash = ripemd160.convert(msg.codeUnits).asHex; 13 | expect(hash, hashes[msg]); 14 | } 15 | } 16 | } 17 | 18 | void main() { 19 | group('RIPEMP160', () { 20 | test('bosselae_testvector', () { 21 | final tc = TestCase({ 22 | "": "9c1185a5c5e9fc54612808977ee8f548b2258d31", 23 | "a": "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", 24 | "abc": "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", 25 | "message digest": "5d0689ef49d2fae572b881b123a85ffa21595f36", 26 | "abcdefghijklmnopqrstuvwxyz": 27 | "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", 28 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq": 29 | "12a053384a9c0c88e405a06c27dcf49ada62eb2b", 30 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789": 31 | "b0e20b6e3116640286ed3a87a5713079b21f5189", 32 | "1234567890" * 8: "9b752e45573d4b39f4dbd3323cab82bf63326bfb", 33 | 'a' * 1000000: '52783243c1697bdbe16d37f97f68f08325dc1528', 34 | }); 35 | tc.perform(); 36 | }); 37 | test('64bytes', () { 38 | final tc = TestCase({ 39 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890^_': 40 | '1ee2a4b162e4dc733b4eaa8b014369846af51c5c', 41 | '''ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890^_abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq()+?#'"!''': 42 | '577c3cde4a49053e808d9332e2ca697818023218', 43 | }); 44 | tc.perform(); 45 | }); 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /test/aes/aes_cbc_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | import 'package:ninja_hex/ninja_hex.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | void main() { 6 | group('AES-128-CBC', () { 7 | final aesKey1 = AESKey.fromHex('B025700C28E7F0F97F7EA8EEEEC29F9F'); 8 | final iv = hexDecoder.convert('B025700C28E7F0F97F7EA8EEEEC29F9F'); 9 | 10 | group('short_padded', () { 11 | test('Encoding', () { 12 | String value = aesKey1.encryptCbcToBase64('hello world!\n', iv: iv); 13 | expect(value, '3Mjz548+yTC9q+gRPF6+Nw=='); 14 | }); 15 | 16 | test('Decode', () { 17 | final decoded = 18 | aesKey1.decryptCbcToUtf8('3Mjz548+yTC9q+gRPF6+Nw==', iv: iv); 19 | expect(decoded, 'hello world!\n'); 20 | }); 21 | }); 22 | 23 | group('short', () { 24 | test('Encoding', () { 25 | String value = aesKey1.encryptCbcToBase64('hello world!!!!\n', iv: iv); 26 | expect(value, 'S+uqDrS44gxjMWS/g+GLD1IrtN28rhuv063miOIaqr8='); 27 | }); 28 | 29 | test('Decode', () { 30 | final decoded = aesKey1.decryptCbcToUtf8( 31 | 'S+uqDrS44gxjMWS/g+GLD1IrtN28rhuv063miOIaqr8=', 32 | iv: iv); 33 | expect(decoded, 'hello world!!!!\n'); 34 | }); 35 | }); 36 | 37 | group('long', () { 38 | test('Encoding', () { 39 | String value = aesKey1.encryptCbcToBase64( 40 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit ........\n', 41 | iv: iv); 42 | expect(value, 43 | 'RehLdYZ1dyyjZEIG8F/7R8wF0oELFxB6tMqVp6T6b/9RaOlireU5qbsFcyfcAVW08hHUC+b6UW61Co+BiWuxvWU0FnksTxs0RTQhEhdyLRI='); 44 | }); 45 | 46 | test('Decode', () { 47 | final decoded = aesKey1.decryptCbcToUtf8( 48 | 'RehLdYZ1dyyjZEIG8F/7R8wF0oELFxB6tMqVp6T6b/9RaOlireU5qbsFcyfcAVW08hHUC+b6UW61Co+BiWuxvWU0FnksTxs0RTQhEhdyLRI=', 49 | iv: iv); 50 | expect(decoded, 51 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit ........\n'); 52 | }); 53 | }); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /test/rsa/signer/rsa_pkcs1v15_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/asymmetric/rsa/encoder/emsaPkcs1v15.dart'; 2 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 3 | import 'package:ninja/asymmetric/rsa/signer/rsassa_pks1_v15.dart'; 4 | import 'package:ninja_openssl/ninja_openssl.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('RSA.Signer.Rsassa', () { 9 | final message = 'abcdefghijklmnopqrstuvwxyz\n'; 10 | 11 | final privateKey = RSAPrivateKey.fromASN1( 12 | 'MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlkNmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAbYQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRkBuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAexIGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAww+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw=='); 13 | final publicKey = privateKey.toPublicKey; 14 | 15 | test('sign&verify', () { 16 | // print(privateKey); 17 | 18 | final signer = RsassaPkcs1v15Signer(hasher: EmsaHasher.sha1); 19 | final signature = signer.signToBase64(privateKey, message); 20 | // print(signature); 21 | expect(signature, 22 | 'kTm+mPFs9T0i2mPLVZuwapMzjaajROKKQoXC2jP6y3CA0m56CUg3eaAW7rwgdgL8P5BJLC8vuBQ/D+MP2FVZPQ=='); 23 | 24 | final verifier = RsassaPkcs1v15Verifier(hasher: EmsaHasher.sha1); 25 | expect(verifier.verify(publicKey, signature, message), true); 26 | }); 27 | 28 | test('sign.openssl', () async { 29 | final signer = RsassaPkcs1v15Signer(hasher: EmsaHasher.sha256); 30 | final signature = signer.signToBase64(privateKey, message); 31 | 32 | expect(await verifyRsaPkcs1(publicKey.toPem(), signature, message), true); 33 | }); 34 | 35 | test('verify.openssl', () async { 36 | final signature = await signRsaPkcs1(privateKey.toPem(), message); 37 | 38 | final verifier = RsassaPkcs1v15Verifier(hasher: EmsaHasher.sha256); 39 | expect(verifier.verify(publicKey, signature, message), true); 40 | }); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /test/rsa/encryption/raw_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('rsa.encryption.raw', () { 6 | final privateKey = RSAPrivateKey.fromASN1( 7 | 'MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlkNmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAbYQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRkBuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAexIGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAww+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw=='); 8 | final publicKey = privateKey.toPublicKey; 9 | 10 | test('small_msg', () { 11 | final message = 'hello world!'; 12 | String encrypted = publicKey.encryptToBase64(message); 13 | expect(encrypted, 14 | 'HqfFR+nuGx7Xf5kCkbTd1QSje7CYWeE3xDO8J+Ed8sW9ER/AN/s84OTZ8K+WSMNkh+P6CM3OiWgprRI+0a5jHg=='); 15 | String decrypted = privateKey.decryptToUtf8(encrypted, raw: true); 16 | expect(decrypted, message); 17 | }); 18 | 19 | test('long_msg', () { 20 | final message = 21 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...'; 22 | String encrypted = publicKey.encryptToBase64(message); 23 | expect(encrypted, 24 | 'UYr82kb5BJ3nm+i1JjE3ad6ni8Jz7CGAG0cENarXaum2a/CnfouejS4HaycXysouYi1U1vqydNFPd3D58rJXr53nRmyWmodn7n6D7EtFo+0T4sumbfyiU5HEhxBP0oi0+9o0w8dAFp1MFKCcfID2NlPD3zyt3fLPfyxXJZxaKlS2EuPuK/t5h2odMC6CVF3Fc/B2oIKOYQzXfAO85Qgwlmxoc5cwXfbQTctIf9P56tv4ZVdGWIQ+2tL/XTrjmKMHDBXImFzsiCdQZouS6tpHxqw5IMh82WcI5COKzDFBC5q5NC9ZgLbQXNnde4gZFls63uGpOLlC6Fgz4pK92YZ3vgu2cp+sL8PDw4rkjWF0X//T0UcSCiJa+rPfLYnEKj3TfVeyWVkpAVnAfYNs/3wov013e6SjhR6puYzTf7v5g3s='); 25 | String decrypted = privateKey.decryptToUtf8(encrypted, raw: true); 26 | expect(decrypted, message); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/signer/rsassa_pks1_v15.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/asymmetric/rsa/encoder/emsaPkcs1v15.dart'; 4 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 5 | import 'package:ninja/asymmetric/rsa/signer/signer.dart'; 6 | import 'package:ninja/ninja.dart'; 7 | import 'package:ninja/utils/big_int.dart'; 8 | import 'package:ninja/utils/iterable.dart'; 9 | 10 | class RsassaPkcs1v15Signer implements RsaSigner { 11 | final EmsaHasher hasher; 12 | 13 | RsassaPkcs1v15Signer({EmsaHasher? hasher}) 14 | : hasher = hasher ?? EmsaHasher.sha256; 15 | 16 | List sign( 17 | final RSAPrivateKey key, final /* String | List | BigInt */ msg) { 18 | List msgBytes; 19 | if (msg is List) { 20 | msgBytes = msg; 21 | } else if (msg is String) { 22 | msgBytes = utf8.encode(msg); 23 | } else if (msg is BigInt) { 24 | msgBytes = bigIntToBytes(msg); 25 | } else { 26 | throw ArgumentError.notNull('msg'); 27 | } 28 | 29 | final encodedMessage = emsaPkcs1v15Encode(msgBytes, key.blockSize, hasher); 30 | 31 | return key.engine.signBlock(encodedMessage); 32 | } 33 | 34 | String signToBase64( 35 | RSAPrivateKey key, /* String | List | BigInt */ msg) { 36 | final bytes = sign(key, msg); 37 | return base64Encode(bytes); 38 | } 39 | } 40 | 41 | class RsassaPkcs1v15Verifier implements RsaVerifier { 42 | final EmsaHasher hasher; 43 | 44 | RsassaPkcs1v15Verifier({EmsaHasher? hasher}) 45 | : hasher = hasher ?? EmsaHasher.sha256; 46 | 47 | bool verify(RSAPublicKey key, /* String | List | BigInt */ signature, 48 | final /* String | List | BigInt */ msg) { 49 | final emDash = key.engine.unsign(signature); 50 | 51 | List msgBytes; 52 | if (msg is List) { 53 | msgBytes = msg; 54 | } else if (msg is String) { 55 | msgBytes = utf8.encode(msg); 56 | } else if (msg is BigInt) { 57 | msgBytes = bigIntToBytes(msg); 58 | } else { 59 | throw Exception('Unknown type'); 60 | } 61 | final encodedMessage = emsaPkcs1v15Encode(msgBytes, key.blockSize, hasher); 62 | 63 | return iterableEquality.equals(emDash, encodedMessage); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/encoder/emsaPkcs1v15.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:crypto/crypto.dart' as crypto; 4 | import 'package:ninja_asn1/ninja_asn1.dart'; 5 | 6 | class EmsaHasher { 7 | final Uint8List asn1ObjectId; 8 | 9 | final String name; 10 | 11 | final crypto.Hash hasher; 12 | 13 | EmsaHasher(this.asn1ObjectId, this.name, this.hasher); 14 | 15 | List hash(List msg) => hasher.convert(msg).bytes; 16 | 17 | static final sha512 = EmsaHasher( 18 | Uint8List.fromList( 19 | [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03]), 20 | 'SHA-512', 21 | crypto.sha512); 22 | 23 | static final sha384 = EmsaHasher( 24 | Uint8List.fromList( 25 | [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02]), 26 | 'SHA-384', 27 | crypto.sha384); 28 | 29 | static final sha256 = EmsaHasher( 30 | Uint8List.fromList( 31 | [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01]), 32 | 'SHA-256', 33 | crypto.sha256); 34 | 35 | static final sha224 = EmsaHasher( 36 | Uint8List.fromList( 37 | [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04]), 38 | 'SHA-224', 39 | crypto.sha224); 40 | 41 | static final sha1 = EmsaHasher( 42 | Uint8List.fromList([0x2b, 0x0e, 0x03, 0x02, 0x1a]), 'SHA-1', crypto.sha1); 43 | 44 | static final md5 = EmsaHasher( 45 | Uint8List.fromList([0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05]), 46 | 'MD5', 47 | crypto.md5); 48 | } 49 | 50 | /// Implements https://tools.ietf.org/html/rfc3447#section-9.2 specification. 51 | List emsaPkcs1v15Encode(List msg, int outLength, EmsaHasher hasher) { 52 | final hashed = hasher.hash(msg); 53 | 54 | final asn1 = ASN1Sequence([ 55 | ASN1Sequence([ 56 | ASN1Unknown(ASN1Type.objectIdentifierTag, hasher.asn1ObjectId), 57 | ASN1Null() 58 | ]), 59 | ASN1OctetString(Uint8List.fromList(hashed)) 60 | ]); 61 | final t = asn1.encode(); 62 | 63 | if (outLength < t.length + 11) { 64 | throw Exception("intended encoded message length too short"); 65 | } 66 | 67 | return [ 68 | 0, 69 | 1, 70 | ...List.filled(outLength - t.length - 3, 255), 71 | 0, 72 | ...t 73 | ]; 74 | } 75 | -------------------------------------------------------------------------------- /example/rsa/pem_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | 3 | final publicKeyPkcs1 = ''' 4 | -----BEGIN RSA PUBLIC KEY----- 5 | MEgCQQDL+0XmsJ8a9A32DdyGW2+Yof1yRni1g7+1roU5Ynv/3Nkw18P5lvdeFRcq 6 | AX8UMQHs0o/GKbgA4k8Kg2Zdd8CjAgMBAAE= 7 | -----END RSA PUBLIC KEY-----'''; 8 | 9 | final publicKeyPkcs8 = ''' 10 | -----BEGIN PUBLIC KEY----- 11 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWD 12 | v7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQ== 13 | -----END PUBLIC KEY-----'''; 14 | 15 | final privateKeyPkcs1 = ''' 16 | -----BEGIN RSA PRIVATE KEY----- 17 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 18 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 19 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 20 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 21 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 22 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 23 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 24 | -----END RSA PRIVATE KEY-----'''; 25 | 26 | final privateKeyPkcs8 = ''' 27 | -----BEGIN PRIVATE KEY----- 28 | MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAy/tF5rCfGvQN9g3c 29 | hltvmKH9ckZ4tYO/ta6FOWJ7/9zZMNfD+Zb3XhUXKgF/FDEB7NKPxim4AOJPCoNm 30 | XXfAowIDAQABAkBhpOsVPz8qm+GDA6eo+WQ2YHT+mxV1bpf61IwZqDdLhwWJ3ecu 31 | Q3fzg3q1n6drVVY2QvLfY12nGjqlCrg1IBthAiEA82UmxX5KemD4l+2C+JXn6M4p 32 | jTdvHb0axkX66Y3qEP8CIQDWi5cA7aZUZGQG6gZd7ej93kA5ePjW9MHwPohQa7xs 33 | XQIhALrNqHstGYZhhIo+TSXzD6GbEUMEB7EgYTtJnHDCbaILAiEAiecNt7YJvKMO 34 | vHb+gq+inFOYOpjscda/Nforym2Fnq0CIDDD4MmhLHzVBCkPyBj8FeOi9p1W1VE4 35 | AtoUW92Y3riz 36 | -----END PRIVATE KEY-----'''; 37 | 38 | void pkcs1() { 39 | final publicKey = RSAPublicKey.fromPEM(publicKeyPkcs1); 40 | print(publicKey.toPem(toPkcs1: true)); 41 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPkcs1); 42 | print(privateKey.toPem()); 43 | print(privateKey.toPem(toPkcs1: false)); 44 | } 45 | 46 | void pkcs8() { 47 | final publicKey = RSAPublicKey.fromPEM(publicKeyPkcs8); 48 | print(publicKey.toPem()); 49 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPkcs8); 50 | print(privateKey.toPem(toPkcs1: false)); 51 | } 52 | 53 | void main() { 54 | pkcs1(); 55 | pkcs8(); 56 | } 57 | -------------------------------------------------------------------------------- /test/rsa/signer/rsa_pss_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 4 | import 'package:ninja_openssl/ninja_openssl.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('RSA.signature.pss', () { 9 | final privateKey = RSAPrivateKey.fromASN1( 10 | 'MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlkNmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAbYQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRkBuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAexIGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAww+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw=='); 11 | final publicKey = privateKey.toPublicKey; 12 | 13 | final messageAbcd = 'abcdefghijklmnopqrstuvwxyz\n'; 14 | 15 | test('sign&verify', () { 16 | final signer = RsaSsaPssSigner(saltLength: 10); 17 | final signature = signer.signToBase64(privateKey, messageAbcd); 18 | 19 | final verifier = RsaSsaPssVerifier(saltLength: 10); 20 | expect(verifier.verify(publicKey, signature, messageAbcd), true); 21 | }); 22 | 23 | test('sign.withSalt', () { 24 | final signer = RsaSsaPssSigner(saltLength: 10); 25 | final signature = signer.signToBase64(privateKey, messageAbcd, 26 | salt: base64Decode('Br7j7BXOigzA4A==')); 27 | expect(signature, 28 | 'ryq2OCyestd7yDKCjZ8wTL6xXf5DKuyuT2HWdz28uIpt2wz8sjPcAj0TuzOskE6HC938iMbn9jFS30Lwr9BN9A=='); 29 | }); 30 | 31 | test('sign.openssl', () async { 32 | final signer = RsaSsaPssSigner(saltLength: 10); 33 | final signature = signer.signToBase64(privateKey, messageAbcd); 34 | 35 | expect( 36 | await verifyRsaPss(publicKey.toPem(), signature, messageAbcd, 37 | saltLength: 10), 38 | true); 39 | }); 40 | 41 | test('verify.constant', () { 42 | final signature = 43 | 'ryq2OCyestd7yDKCjZ8wTL6xXf5DKuyuT2HWdz28uIpt2wz8sjPcAj0TuzOskE6HC938iMbn9jFS30Lwr9BN9A=='; 44 | final verifier = RsaSsaPssVerifier(saltLength: 10); 45 | expect(verifier.verify(publicKey, signature, messageAbcd), true); 46 | expect(verifier.extractSalt(publicKey, signature), 'Br7j7BXOigzA4A=='); 47 | }); 48 | 49 | test('verify.openssl', () async { 50 | final signature = 51 | await signRsaPss(privateKey.toPem(), messageAbcd, saltLength: 10); 52 | final verifier = RsaSsaPssVerifier(saltLength: 10); 53 | expect(verifier.verify(publicKey, signature, messageAbcd), true); 54 | }); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/engine/encrypter.dart: -------------------------------------------------------------------------------- 1 | // [RSAEncryptionEngine] and [RSADecryptionEngine] are copied and modified from 2 | // pointy_castles package. See file LICENSE/pointy_castle_LICENSE 3 | // file for more information. 4 | 5 | import 'dart:convert'; 6 | import 'dart:typed_data'; 7 | 8 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 9 | import 'package:ninja/utils/big_int.dart'; 10 | 11 | class RSAEncryptionEngine { 12 | final RSAPublicKey key; 13 | 14 | final int blockSize; 15 | 16 | final int bitSize; 17 | 18 | RSAEncryptionEngine(this.key) 19 | : bitSize = key.n.bitLength, 20 | blockSize = (key.n.bitLength + 7) ~/ 8; 21 | 22 | Iterable process(Iterable data) { 23 | final numBlocks = (data.length / blockSize).ceil(); 24 | final out = Uint8List(numBlocks * blockSize); 25 | int outOffset = 0; 26 | for (int i = 0; i < numBlocks; i++) { 27 | Iterable curInputBlock; 28 | if (i == numBlocks - 1) { 29 | curInputBlock = data; 30 | } else { 31 | curInputBlock = data.take(blockSize); 32 | } 33 | outOffset += processBlock(curInputBlock, out, outOffset); 34 | data = data.skip(blockSize); 35 | } 36 | 37 | return out; 38 | } 39 | 40 | int processBlock(Iterable inputBlock, Uint8List out, int outOff) { 41 | final input = _convertInput(inputBlock); 42 | BigInt output = input.modPow(key.e, key.n); 43 | return _convertOutput(output, out, outOff); 44 | } 45 | 46 | List unsign(final /* BigInt | Iterable | String */ message) { 47 | BigInt input; 48 | if (message is BigInt) { 49 | input = message; 50 | } else if (message is Iterable) { 51 | input = _convertInput(message); 52 | } else if (message is String) { 53 | input = _convertInput(base64Decode(message)); 54 | } else { 55 | throw ArgumentError('Unknown type'); 56 | } 57 | final signedBigInt = input.modPow(key.e, key.n); 58 | final ret = bigIntToBytes(signedBigInt, outLen: blockSize); 59 | return ret; 60 | } 61 | 62 | BigInt _convertInput(Iterable input) { 63 | if (input.length > blockSize) { 64 | throw ArgumentError("Input too large for RSA cipher"); 65 | } 66 | 67 | BigInt res = bytesToBigInt(input); 68 | if (res >= key.n) { 69 | throw ArgumentError("Input too large for RSA cipher"); 70 | } 71 | 72 | return res; 73 | } 74 | 75 | int _convertOutput(BigInt result, Uint8List out, int offset) { 76 | final Uint8List output = bigIntToBytes(result); 77 | out.setAll(offset + (blockSize - output.length), output); 78 | return blockSize; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/rsa/pem_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('rsa.pem', () { 6 | final publicKeyPkcs1 = ''' 7 | -----BEGIN RSA PUBLIC KEY----- 8 | MEgCQQDL+0XmsJ8a9A32DdyGW2+Yof1yRni1g7+1roU5Ynv/3Nkw18P5lvdeFRcq 9 | AX8UMQHs0o/GKbgA4k8Kg2Zdd8CjAgMBAAE= 10 | -----END RSA PUBLIC KEY-----'''; 11 | 12 | final publicKeyPkcs8 = ''' 13 | -----BEGIN PUBLIC KEY----- 14 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWD 15 | v7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQ== 16 | -----END PUBLIC KEY-----'''; 17 | 18 | final privateKeyPkcs1 = ''' 19 | -----BEGIN RSA PRIVATE KEY----- 20 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 21 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 22 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 23 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 24 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 25 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 26 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 27 | -----END RSA PRIVATE KEY-----'''; 28 | 29 | final privateKeyPkcs8 = ''' 30 | -----BEGIN PRIVATE KEY----- 31 | MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAy/tF5rCfGvQN9g3c 32 | hltvmKH9ckZ4tYO/ta6FOWJ7/9zZMNfD+Zb3XhUXKgF/FDEB7NKPxim4AOJPCoNm 33 | XXfAowIDAQABAkBhpOsVPz8qm+GDA6eo+WQ2YHT+mxV1bpf61IwZqDdLhwWJ3ecu 34 | Q3fzg3q1n6drVVY2QvLfY12nGjqlCrg1IBthAiEA82UmxX5KemD4l+2C+JXn6M4p 35 | jTdvHb0axkX66Y3qEP8CIQDWi5cA7aZUZGQG6gZd7ej93kA5ePjW9MHwPohQa7xs 36 | XQIhALrNqHstGYZhhIo+TSXzD6GbEUMEB7EgYTtJnHDCbaILAiEAiecNt7YJvKMO 37 | vHb+gq+inFOYOpjscda/Nforym2Fnq0CIDDD4MmhLHzVBCkPyBj8FeOi9p1W1VE4 38 | AtoUW92Y3riz 39 | -----END PRIVATE KEY-----'''; 40 | 41 | test('publickey.pkcs1', () { 42 | final publicKey = RSAPublicKey.fromPEM(publicKeyPkcs1); 43 | final encoded = publicKey.toPem(toPkcs1: true); 44 | expect(encoded, publicKeyPkcs1); 45 | }); 46 | 47 | test('publickey.pkcs8', () { 48 | final publicKey = RSAPublicKey.fromPEM(publicKeyPkcs8); 49 | final encoded = publicKey.toPem(); 50 | expect(encoded, publicKeyPkcs8); 51 | }); 52 | 53 | test('privatekey.pkcs1', () { 54 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPkcs1); 55 | final encoded = privateKey.toPem(toPkcs1: true); 56 | expect(encoded, privateKeyPkcs1); 57 | }); 58 | 59 | test('privatekey.pkcs8', () { 60 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPkcs8); 61 | final encoded = privateKey.toPem(toPkcs1: false); 62 | expect(encoded, privateKeyPkcs8); 63 | }); 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /test/rsa/encryption/oaep_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/ninja.dart'; 4 | import 'package:ninja_openssl/ninja_openssl.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('rsa.oaep', () { 9 | final privateKey = RSAPrivateKey.fromASN1( 10 | 'MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlkNmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAbYQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRkBuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAexIGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAww+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw=='); 11 | final publicKey = privateKey.toPublicKey; 12 | 13 | final smallMsg = 'hello world!\n'; 14 | 15 | test('smallmsg.encrypt&decrypt', () { 16 | String encrypted = publicKey.encryptOaepToBase64(smallMsg); 17 | print(encrypted); 18 | String decrypted = privateKey.decryptOaepToUtf8(encrypted); 19 | 20 | expect(decrypted, smallMsg); 21 | }); 22 | 23 | test('smallmsg.encrypt.openssl', () async { 24 | String encrypted = publicKey.encryptOaepToBase64(smallMsg); 25 | print(encrypted); 26 | 27 | expect( 28 | utf8.decode(await decryptRsaOaep(privateKey.toPem(), encrypted, 29 | cleanupTempDirectory: false)), 30 | smallMsg); 31 | }); 32 | 33 | test('smallmsg.decrypt.constant', () { 34 | String encrypted = 35 | 'WwOeW77CHGzwB76RgmDbpJuyRWAVJnz/b1Vzd4UQbt/BTl8PKuuLWjQYxkeA3NtV8zfSzzJVmkLlQafCr2RK+Q=='; 36 | final decoded = privateKey.decryptOaepToUtf8(encrypted); 37 | expect(decoded, smallMsg); 38 | }); 39 | 40 | test('smallmsg.decrypt.openssl', () async { 41 | final encrypted = await encryptRsaOaep(publicKey.toPem(), smallMsg, 42 | cleanupTempDirectory: false); 43 | print(base64Encode(encrypted)); 44 | String decrypted = privateKey.decryptOaepToUtf8(encrypted); 45 | expect(decrypted, smallMsg); 46 | }); 47 | 48 | test('long_msg_endecrypt', () { 49 | final message = 50 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...'; 51 | String encrypted = publicKey.encryptOaepToBase64(message); 52 | print(encrypted); 53 | String decrypted = privateKey.decryptOaepToUtf8(encrypted); 54 | 55 | expect(decrypted, message); 56 | }); 57 | }); 58 | } 59 | -------------------------------------------------------------------------------- /test/rsa/encryption/pkcs1v15_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:ninja/ninja.dart'; 4 | import 'package:ninja_hex/ninja_hex.dart'; 5 | import 'package:ninja_openssl/ninja_openssl.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | void main() { 9 | group('rsa.encryption.raw', () { 10 | final privateKey = RSAPrivateKey.fromASN1( 11 | 'MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlkNmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAbYQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRkBuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAexIGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAww+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw=='); 12 | final publicKey = privateKey.toPublicKey; 13 | 14 | final smallMsg = 'hello world!\n'; 15 | final longMsg = 16 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...Lorem ipsum dolor sit amet, consectetur adipiscing elit...\n'; 17 | 18 | test('smallMsg.encrypt&decrypt', () { 19 | String encrypted = publicKey.encryptPkcs1v15ToBase64(smallMsg); 20 | print(publicKey.encryptPkcs1v15ToBase64(smallMsg)); 21 | String decrypted = privateKey.decryptPkcs1v15ToUtf8(encrypted); 22 | 23 | expect(decrypted, smallMsg); 24 | }); 25 | 26 | test('smallMsg.dencrypt.constant', () { 27 | final encrypted = hexDecode( 28 | '253D6BCFBE654D5B07179719ECB250218AFEBCF555FD6CC56C3C64838BE719B44484C7916106B81C722AF245886172A5233B44234B36E61186CA77E513404514'); 29 | final decoded = privateKey.decryptPkcs1v15ToUtf8(encrypted); 30 | expect(decoded, smallMsg); 31 | }); 32 | 33 | test('smallMsg.dencrypt.openssl', () async { 34 | final encrypted = await encryptRsaPkcs1v15(publicKey.toPem(), smallMsg); 35 | final decoded = privateKey.decryptPkcs1v15ToUtf8(encrypted); 36 | expect(decoded, smallMsg); 37 | }); 38 | 39 | test('smallMsg.encrypt.openssl', () async { 40 | final encrypted = publicKey.encryptPkcs1v15ToBase64(smallMsg); 41 | 42 | expect( 43 | utf8.decode(await decryptRsaPkcs1v15(privateKey.toPem(), encrypted)), 44 | smallMsg); 45 | }); 46 | 47 | test('longMsg.encrypt&decrypt', () { 48 | String encrypted = publicKey.encryptPkcs1v15ToBase64(longMsg); 49 | print(publicKey.encryptPkcs1v15ToBase64(longMsg)); 50 | String decrypted = privateKey.decryptPkcs1v15ToUtf8(encrypted); 51 | 52 | expect(decrypted, longMsg); 53 | }); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /lib/block_cipher/modes/cbc.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:ninja/ninja.dart'; 5 | import 'package:ninja/utils/listops.dart'; 6 | 7 | final cbcBlockCipherMode = CbcBlockCipherMode(); 8 | 9 | class CbcBlockCipherMode { 10 | CbcBlockCipherMode(); 11 | 12 | Uint8List encrypt(BlockCipher cipher, /* String | Iterable */ input, 13 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 14 | Iterable mangler; 15 | if (iv != null) { 16 | if (iv.length != cipher.blockSize) { 17 | throw Exception('Invalid initial vector length'); 18 | } 19 | mangler = iv; 20 | } else { 21 | mangler = Uint8List(cipher.blockSize); 22 | } 23 | 24 | if (input is String) { 25 | input = utf8.encode(input); 26 | } 27 | final padded = padder.pad(cipher.blockSize, input); 28 | 29 | final numBlocks = (padded.length / cipher.blockSize).ceil(); 30 | final out = Uint8List(numBlocks * cipher.blockSize); 31 | 32 | int offset = 0; 33 | for (int i = 0; i < numBlocks; i++) { 34 | final inputBlock = 35 | ListOps.xor(padded.skip(offset).take(cipher.blockSize), mangler) 36 | .buffer 37 | .asByteData(); 38 | final outputBlock = out.buffer.asByteData(offset, cipher.blockSize); 39 | cipher.processBlock(inputBlock, outputBlock); 40 | mangler = out.skip(offset).take(cipher.blockSize); 41 | offset += cipher.blockSize; 42 | } 43 | 44 | return out; 45 | } 46 | 47 | Iterable decrypt(BlockCipher cipher, /* String | Uint8List */ input, 48 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 49 | Iterable mangler; 50 | if (iv != null) { 51 | if (iv.length != cipher.blockSize) { 52 | throw Exception('Invalid initial vector length'); 53 | } 54 | mangler = iv; 55 | } else { 56 | mangler = Uint8List(cipher.blockSize); 57 | } 58 | 59 | if (input is String) { 60 | input = base64Decode(input); 61 | } 62 | 63 | final numBlocks = (input.length / cipher.blockSize).ceil(); 64 | final decrypted = Uint8List(numBlocks * cipher.blockSize); 65 | 66 | int offset = 0; 67 | for (int i = 0; i < numBlocks; i++) { 68 | final inputBlock = input.buffer.asByteData(offset, cipher.blockSize); 69 | final outputBlock = decrypted.buffer.asByteData(offset, cipher.blockSize); 70 | cipher.processBlock(inputBlock, outputBlock); 71 | ListOps.xorToByteData(outputBlock, mangler); 72 | mangler = input.skip(offset).take(cipher.blockSize); 73 | offset += cipher.blockSize; 74 | } 75 | 76 | final unpadded = padder.unpad(cipher.blockSize, decrypted).toList(); 77 | 78 | return unpadded; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/utils/big_int.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:ninja_hex/ninja_hex.dart'; 5 | 6 | /// Decodes the provided [BigInt] from bytes. 7 | /// This is OS2IP as defined in rfc3447. 8 | BigInt bytesToBigInt(Iterable bytes, {Endian endian = Endian.big}) { 9 | BigInt result = BigInt.from(0); 10 | if (endian == Endian.little) { 11 | bytes = bytes.toList().reversed; 12 | } 13 | 14 | for (int byte in bytes) { 15 | result = result << 8; 16 | result |= BigInt.from(byte); 17 | } 18 | 19 | return result; 20 | } 21 | 22 | /// Encode a BigInt into bytes using big-endian encoding. 23 | /// This is I2OSP as defined in rfc3447. 24 | Uint8List bigIntToBytes(BigInt number, 25 | {int? outLen, Endian endian = Endian.big}) { 26 | int size = (number.bitLength + 7) >> 3; 27 | if (outLen == null) { 28 | outLen = size; 29 | } else if (outLen < size) { 30 | throw Exception('Number too large'); 31 | } 32 | final result = Uint8List(outLen); 33 | int pos = endian == Endian.big ? outLen - 1 : 0; 34 | for (int i = 0; i < size; i++) { 35 | result[pos] = (number & _byteMask).toInt(); 36 | if (endian == Endian.big) { 37 | pos -= 1; 38 | } else { 39 | pos += 1; 40 | } 41 | number = number >> 8; 42 | } 43 | return result; 44 | } 45 | 46 | extension BigIntUint8List on BigInt { 47 | Uint8List asBytes({int? outLen, Endian endian = Endian.big}) => 48 | bigIntToBytes(this, outLen: outLen, endian: endian); 49 | } 50 | 51 | extension Uint8ListBigInt on Iterable { 52 | BigInt asBigInt({Endian endian = Endian.big}) => 53 | bytesToBigInt(this, endian: endian); 54 | 55 | String toHex({int? outLen, Endian endian = Endian.big}) => 56 | (endian == Endian.big ? this : this.toList().reversed) 57 | .map((e) => e.hexByte) 58 | .join() 59 | .padLeft(outLen ?? 0, '0'); 60 | } 61 | 62 | // Not handling negative numbers. Decide how you want to do that. 63 | 64 | final _byteMask = BigInt.from(0xff); 65 | 66 | BigInt base64ToBigInt(String input) { 67 | final bytes = base64.decode(input); 68 | return bytesToBigInt(bytes); 69 | } 70 | 71 | String bigIntToBase64(BigInt input) { 72 | final bytes = bigIntToBytes(input); 73 | return base64.encode(bytes); 74 | } 75 | 76 | String intStringToHex(String input) { 77 | return hexEncode(bigIntToBytes(BigInt.parse(input))); 78 | } 79 | 80 | String hexToIntString(String input) { 81 | return bytesToBigInt(hexDecode(input)).toRadixString(10); 82 | } 83 | 84 | String bigIntToHex(BigInt input) { 85 | return hexEncode(bigIntToBytes(input)); 86 | } 87 | 88 | BigInt hexToBigInt(String input) { 89 | return bytesToBigInt(hexDecode(input)); 90 | } 91 | 92 | extension IntHex on int { 93 | String get hexByte { 94 | if (this > 255) { 95 | throw Exception('invalid byte value. must be <= 255'); 96 | } 97 | return toRadixString(16).padLeft(2, '0'); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /example/example.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | 3 | main() { 4 | final pubKey = RSAPublicKey( 5 | BigInt.parse( 6 | "20620915813302906913761247666337410938401372343750709187749515126790853245302593205328533062154315527282056175455193812046134139935830222032257750866653461677566720508752544506266533943725970345491747964654489405936145559121373664620352701801574863309087932865304205561439525871868738640172656811470047745445089832193075388387376667722031640892525639171016297098395245887609359882693921643396724693523583076582208970794545581164952427577506035951122669158313095779596666008591745562008787129160302313244329988240795948461701615228062848622019620094307696506764461083870202605984497833670577046553861732258592935325691"), 7 | BigInt.parse("65537")); 8 | 9 | final privKey = RSAPrivateKey( 10 | BigInt.parse( 11 | "20620915813302906913761247666337410938401372343750709187749515126790853245302593205328533062154315527282056175455193812046134139935830222032257750866653461677566720508752544506266533943725970345491747964654489405936145559121373664620352701801574863309087932865304205561439525871868738640172656811470047745445089832193075388387376667722031640892525639171016297098395245887609359882693921643396724693523583076582208970794545581164952427577506035951122669158313095779596666008591745562008787129160302313244329988240795948461701615228062848622019620094307696506764461083870202605984497833670577046553861732258592935325691"), 12 | BigInt.parse("65537"), 13 | BigInt.parse( 14 | "11998058528661160053642124235359844880039079149364512302169225182946866898849176558365314596732660324493329967536772364327680348872134489319530228055102152992797567579226269544119435926913937183793755182388650533700918602627770886358900914370472445911502526145837923104029967812779021649252540542517598618021899291933220000807916271555680217608559770825469218984818060775562259820009637370696396889812317991880425127772801187664191059506258517954313903362361211485802288635947903604738301101038823790599295749578655834195416886345569976295245464597506584866355976650830539380175531900288933412328525689718517239330305"), 15 | BigInt.parse( 16 | "144173682842817587002196172066264549138375068078359231382946906898412792452632726597279520229873489736777248181678202636100459215718497240474064366927544074501134727745837254834206456400508719134610847814227274992298238973375146473350157304285346424982280927848339601514720098577525635486320547905945936448443"), 17 | BigInt.parse( 18 | "143028293421514654659358549214971921584534096938352096320458818956414890934365483375293202045679474764569937266017713262196941957149321696805368542065644090886347646782188634885321277533175667840285448510687854061424867903968633218073060468434469761149335255007464091258725753837522484082998329871306803923137")); 19 | 20 | String encoded = pubKey.encryptToBase64( 21 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 22 | print(encoded); 23 | String decoded = privKey.decryptToUtf8(encoded); 24 | print(decoded); 25 | } 26 | -------------------------------------------------------------------------------- /lib/block_cipher/modes/ctr.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'dart:convert'; 3 | import 'dart:math'; 4 | import 'dart:typed_data'; 5 | 6 | import 'package:ninja/ninja.dart'; 7 | 8 | final ctrBlockCipherMode = CTRBlockCipherMode(); 9 | 10 | class CTRBlockCipherMode { 11 | CTRBlockCipherMode(); 12 | 13 | Uint8List encrypt(BlockCipher cipher, /* String | Iterable */ input, 14 | {required Uint8List iv, Padder? padder}) { 15 | if (input is String) { 16 | input = utf8.encode(input); 17 | } 18 | 19 | Uint8List padded; 20 | if (padder != null) { 21 | padded = padder.pad(cipher.blockSize, input); 22 | } else { 23 | padded = Uint8List.fromList(input); 24 | } 25 | 26 | final state = CTRState(cipher, iv); 27 | final out = Uint8List(padded.length); 28 | 29 | for (int i = 0; i < padded.length; i++) { 30 | final ebyte = state.nextByte; 31 | out[i] = padded[i] ^ ebyte; 32 | // Debug print('Encrypt: inp: ${padded[i]}, ebyte: ${ebyte}, out: ${out[i]}'); 33 | } 34 | 35 | return out; 36 | } 37 | 38 | Uint8List decrypt(BlockCipher cipher, /* String | Uint8List */ input, 39 | {required Uint8List iv, Padder? padder}) { 40 | Uint8List inp; 41 | if (input is String) { 42 | inp = base64Decode(input); 43 | } else { 44 | inp = input; 45 | } 46 | 47 | final state = CTRState(cipher, iv); 48 | var out = Uint8List(inp.length); 49 | 50 | for (int i = 0; i < inp.length; i++) { 51 | final ebyte = state.nextByte; 52 | out[i] = inp[i] ^ ebyte; 53 | // Debug print('Decrypt: inp: ${inp[i]}, ebyte: ${ebyte}, out: ${out[i]}'); 54 | } 55 | 56 | if (padder != null) { 57 | out = Uint8List.fromList(padder.unpad(cipher.blockSize, out).toList()); 58 | } 59 | 60 | return out; 61 | } 62 | 63 | static Uint8List makeRandomIV({Random? random}) { 64 | random ??= Random.secure(); 65 | return Uint8List.fromList(List.generate(16, (i) => random!.nextInt(256))); 66 | } 67 | } 68 | 69 | class CTRState { 70 | final BlockCipher cipher; 71 | 72 | final Uint8List _counter; 73 | 74 | final Queue encryptedCounterBuffer; 75 | 76 | CTRState(this.cipher, Uint8List counter, 77 | {Iterable encryptedCounterBuffer = const []}) 78 | : _counter = Uint8List.fromList(counter), 79 | encryptedCounterBuffer = Queue.from(encryptedCounterBuffer); 80 | 81 | int get nextByte { 82 | if (encryptedCounterBuffer.isEmpty) { 83 | _refill(); 84 | } 85 | return encryptedCounterBuffer.removeFirst(); 86 | } 87 | 88 | void _refill() { 89 | final out = Uint8List(cipher.blockSize); 90 | cipher.processBlock(_counter.buffer.asByteData(), out.buffer.asByteData()); 91 | encryptedCounterBuffer.addAll(out); 92 | incrementCounter(_counter); 93 | } 94 | 95 | static void incrementCounter(Uint8List counter) { 96 | for (int i = counter.length - 1; i >= 0; i--) { 97 | counter[i]++; 98 | if (counter[i] != 0) { 99 | break; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /lib/padder/emePkcs1v15.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:typed_data'; 3 | 4 | import 'padder.dart'; 5 | 6 | class EmePkcs1v15Encoder implements Padder, IndividualBlockPadder { 7 | final Random rand; 8 | 9 | EmePkcs1v15Encoder({Random? rand}) : rand = rand ?? Random.secure(); 10 | 11 | /// Pads a single block 12 | void padBlock(int blockSize, Iterable block, ByteData output) { 13 | if (output.lengthInBytes != blockSize) { 14 | throw Exception('Invalid buffer size'); 15 | } 16 | 17 | if (block.length > blockSize - 11) { 18 | throw Exception('block too long'); 19 | } 20 | 21 | output.setUint8(0, 0); 22 | output.setUint8(1, 2); 23 | 24 | int i = 2; 25 | final psLen = blockSize - block.length - 3; 26 | for (int j = 0; j < psLen; j++) { 27 | int r = rand.nextInt(256); 28 | while (r == 0) { 29 | r = rand.nextInt(256); 30 | } 31 | output.setUint8(i++, r); 32 | } 33 | 34 | output.setUint8(i++, 0); 35 | 36 | for (int byte in block) { 37 | output.setUint8(i++, byte); 38 | } 39 | } 40 | 41 | Uint8List pad(int blockSize, Iterable input) { 42 | int numBlocks = (input.length / (blockSize - 11)).ceil(); 43 | final output = Uint8List(numBlocks * blockSize); 44 | 45 | for (int i = 0; i < numBlocks; i++) { 46 | Iterable block; 47 | if (i == numBlocks - 1) { 48 | block = input; 49 | } else { 50 | block = input.take(blockSize - 11); 51 | input = input.skip(blockSize - 11); 52 | } 53 | padBlock( 54 | blockSize, block, output.buffer.asByteData(i * blockSize, blockSize)); 55 | } 56 | 57 | return output; 58 | } 59 | 60 | Iterable unpadBlock(int blockSize, Iterable block) { 61 | if (block.length != blockSize) { 62 | throw Exception('Invalid blocksize'); 63 | } 64 | 65 | if (block.elementAt(0) != 0) { 66 | throw Exception('Invalid block. First byte not 0'); 67 | } 68 | 69 | if (block.elementAt(1) != 2) { 70 | throw Exception('Invalid block. Second byte not 2'); 71 | } 72 | 73 | block = block.skip(2); 74 | 75 | block = block.skipWhile((v) => v != 0); 76 | 77 | if (block.isEmpty) { 78 | throw Exception('Invalid block. No Message delimiter found'); 79 | } 80 | 81 | block = block.skip(1); 82 | 83 | // TODO is this an error? 84 | if (block.isEmpty) { 85 | throw Exception('Invalid block. No Message'); 86 | } 87 | 88 | return block; 89 | } 90 | 91 | Iterable unpad(int blockSize, Iterable input) { 92 | if (input.length % blockSize != 0) { 93 | throw Exception( 94 | 'Invalid message length. Must be multiple of blockSize $blockSize. Got ${input.length}'); 95 | } 96 | 97 | final numBlocks = input.length ~/ blockSize; 98 | 99 | final out = Uint8List(numBlocks * (blockSize - 11)); 100 | int outLen = 0; 101 | 102 | for (int i = 0; i < numBlocks; i++) { 103 | Iterable block = input.take(blockSize); 104 | input = input.skip(blockSize); 105 | final unpaddedMsg = unpadBlock(blockSize, block); 106 | out.setAll(i * (blockSize - 11), unpaddedMsg); 107 | outLen += unpaddedMsg.length; 108 | } 109 | 110 | if (outLen == out.length) { 111 | return out; 112 | } 113 | 114 | return out.take(outLen); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/engine/decrypter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 4 | import 'package:ninja/utils/big_int.dart'; 5 | 6 | class RSADecryptionEngine { 7 | final RSAPrivateKey _key; 8 | BigInt _dP; 9 | BigInt _dQ; 10 | BigInt _qInv; 11 | 12 | final int blockSize; 13 | 14 | final int bitSize; 15 | 16 | RSADecryptionEngine._( 17 | this._key, this._dP, this._dQ, this._qInv, this.blockSize, this.bitSize); 18 | 19 | factory RSADecryptionEngine(RSAPrivateKey key) { 20 | final bitSize = key.n.bitLength; 21 | final blockSize = (key.n.bitLength + 7) >> 3; 22 | BigInt pSub1 = (key.p - BigInt.one); 23 | BigInt qSub1 = (key.q - BigInt.one); 24 | BigInt dP = key.d.remainder(pSub1); 25 | BigInt dQ = key.d.remainder(qSub1); 26 | BigInt qInv = key.q.modInverse(key.p); 27 | 28 | return RSADecryptionEngine._(key, dP, dQ, qInv, blockSize, bitSize); 29 | } 30 | 31 | Iterable process(Iterable data, {bool dontPadLastBlock = false}) { 32 | final numBlocks = (data.length / blockSize).ceil(); 33 | final out = Uint8List(numBlocks * blockSize); 34 | int outOffset = 0; 35 | for (int i = 0; i < numBlocks; i++) { 36 | Iterable curInputBlock; 37 | if (i == numBlocks - 1) { 38 | curInputBlock = data; 39 | } else { 40 | curInputBlock = data.take(blockSize); 41 | } 42 | if (dontPadLastBlock && i == numBlocks - 1) { 43 | int outBlockLen = processBlock(curInputBlock, out, outOffset, 44 | dontPad: dontPadLastBlock); 45 | outOffset += outBlockLen; 46 | } else { 47 | processBlock(curInputBlock, out, outOffset); 48 | outOffset += blockSize; 49 | } 50 | data = data.skip(blockSize); 51 | } 52 | 53 | if (!dontPadLastBlock || outOffset == out.length) { 54 | return out; 55 | } 56 | 57 | return out.sublist(0, outOffset); 58 | } 59 | 60 | int processBlock(Iterable inputBlock, Uint8List out, int outOff, 61 | {bool dontPad = false}) { 62 | BigInt input = _convertInput(inputBlock); 63 | BigInt output = _processBigInteger(input); 64 | return _convertOutput(output, out, outOff, dontPad: dontPad); 65 | } 66 | 67 | List signBlock(final /* BigInt | Iterable */ message) { 68 | BigInt input; 69 | if (message is BigInt) { 70 | input = message; 71 | } else if (message is Iterable) { 72 | input = _convertInput(message); 73 | } else { 74 | throw ArgumentError('Unknown type'); 75 | } 76 | final signedBigInt = input.modPow(_key.d, _key.n); 77 | return bigIntToBytes(signedBigInt); 78 | } 79 | 80 | BigInt _convertInput(Iterable input) { 81 | if (input.length > blockSize) { 82 | throw ArgumentError("Input too large for RSA cipher"); 83 | } 84 | 85 | BigInt res = bytesToBigInt(input); 86 | if (res >= _key.n) throw ArgumentError("Input too large for RSA cipher"); 87 | 88 | return res; 89 | } 90 | 91 | int _convertOutput(BigInt result, Uint8List out, int outOff, 92 | {bool dontPad = false}) { 93 | final Uint8List output = bigIntToBytes(result); 94 | if (dontPad || output.length == blockSize) { 95 | out.setAll(outOff, output); 96 | return output.length; 97 | } 98 | out.setAll(outOff + (blockSize - output.length), output); 99 | return blockSize; 100 | } 101 | 102 | BigInt _processBigInteger(BigInt input) { 103 | BigInt mP = (input.remainder(_key.p)).modPow(_dP, _key.p); 104 | 105 | BigInt mQ = (input.remainder(_key.q)).modPow(_dQ, _key.q); 106 | 107 | BigInt h = mP - mQ; 108 | h = h * _qInv; 109 | h = h % _key.p; 110 | 111 | BigInt m = h * _key.q; 112 | m = m + mQ; 113 | 114 | return m; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /test/rsa_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:ninja/ninja.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | group('rsa', () { 6 | group('PublicKey', () { 7 | test('fromASN1', () { 8 | final key = RSAPublicKey.fromASN1( 9 | 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANsFjQ22G36v8jGhcOtCnWtkuqqI9mWOq5I6Gy4NBb46ch2+gXL8/sC37X2BGASnt2YymAm7xwS2+QE89YYvDdECAwEAAQ=='); 10 | expect(key.n.toString(), 11 | '11471096350072129820579819100426547181616187185658504704996065334930805271197099322753245009150228584617512330162571541229290378786994493391408050685808081'); 12 | expect(key.e.toString(), '65537'); 13 | }); 14 | }); 15 | 16 | group('PrivateKey.fromASN1', () { 17 | test('pkcs#1', () { 18 | final key = RSAPrivateKey.fromASN1( 19 | 'MIICXQIBAAKBgQDzskNxV392BhufbSVyC3whpO71XOHf3/DWPyUfNKG1ca7EhVqRRFKfFNXubYevjA2VeXCEU2RNa5NmHL8PmHyr22weDD2KJ0YZBE9RzPs/uh1SX8Nz9ZbLSOpvj49W4io6vT2rp5+Bbv26LhC/zG8dN5eTX9Ftohl5H0tdjNL7KwIDAQABAoGAQPFbqcPQkupTyCu1E+xdmzWx/K9Q/nFWZDIVuXg0M/9kvLhxB0922TAbRtvnke+32wKu6oSysTMe59J3VDel2T2N5F2PoFdcWmD9p5VPMIEKEBuAKOmLcH5MQz2rS2NZ0NB8bEkGHey2Wg8z3J6mYgUMuEw7fx1//npESPaoksECQQD+KMMR/qKbP1iaUFBSLDkL3WatyV1DTaG41PQpTHqoCNK/VQaTe1oPDLIqCe2Ns+4zlGjnWDTfP0RTeZmaLIjhAkEA9XYaJ1kg/c4tDaLjH68W3A/a9loe/0OMPlrolkmHXPRjsVFdOBsU0gUSbeqXwKid8LJ0WNhF5QhwAp0y6KzJiwJAGaRbKfGazjbx5X+82s2DY+MOfPIX6rZmXpN9nr0Mku9w88TMSQzk5SfOwdcGlIlWuvV6L/0COJPVfOaDzL45gQJBAOCNBGwOu4G0hb69zq2DjZQP5S4NT+IRt1Cr9a7W4UCGSlVCq9bR34AqJ6vqOp2DI8m4V3uXjolx6JZbnOECgPUCQQC+CM/Tz3UyGYoSg6o/yTqZ153qzFBJ0XcyWWwaRz9JGNrCdbYXb1DTPXO6SBWCLDOCqdbMyZMPtOOS6V0FbbU6'); 20 | expect(key.n.toString(), 21 | '171129390732660146419855445296498843421793035030054831713262981408625437665094702312259284413650823228768400998091771955907248594823945968177282058399113440833717891845878510897107129982740734254769006318233816359540806364511460644786857687183121930295493705392002305111095244518677061258616435153725547543339'); 22 | expect(key.e.toString(), '65537'); 23 | expect(key.d.toString(), 24 | '45604388500326677407003301220735650096306137858002466330044676599503231286462288110282869253771329595349804285085872060209043696058718225341657859681409215971891059140039798588354778837282844347377082841148663576431973647684265700447716249156331224982434547267381784694326011259136737257925826558124460905153'); 25 | expect(key.p.toString(), 26 | '13311398800872123545509265659481938261907941937028495771208440340566859520917728290659412695924049986718341601969223777955429912069271339711686707239487713'); 27 | expect(key.q.toString(), 28 | '12855853339879521453788356377992413936990740503119663040008894782605651726660339873651248325834950126916952352810922413550188676566583744808486210819115403'); 29 | }); 30 | test('pkcs#8', () { 31 | final key = RSAPrivateKey.fromASN1( 32 | 'MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2wWNDbYbfq/yMaFw60Kda2S6qoj2ZY6rkjobLg0FvjpyHb6Bcvz+wLftfYEYBKe3ZjKYCbvHBLb5ATz1hi8N0QIDAQABAkEAtR0oATigD+kLDEOGDuVtK4uGWNMdfem2sxrdsv0NzLkcWZ6u6XRfq1G7dCagiGom4B93y6UR0KYQvPGLD+DHiQIhAO16txmxxKLU7XJ5Mj7vCg88EpU5DjptyT7GDM0dHADXAiEA7BpT3JnuY5M0RTuHSzcaqSB8p2oVP3h60ebnwHsVCZcCIBx5ZE7uY7dqdHYPVhj5rGkbONcvmicjVsfyE0LcxKjNAiEAjzw9qjScoj441NOTdbcdboNt/GboMxRVdqgd6vEAx0sCIEifY2LV3oO4JJCUN8aRjFJlAXe1vTnDnQLOD/u844Ed', 33 | fromPkcs1: false); 34 | print(key); 35 | 36 | expect(key.n.toString(), 37 | '11471096350072129820579819100426547181616187185658504704996065334930805271197099322753245009150228584617512330162571541229290378786994493391408050685808081'); 38 | expect(key.e.toString(), '65537'); 39 | expect(key.d.toString(), 40 | '9485704191461449311022822471710885422898632045097837923349508899724431403134778704337322169999541158279872714205624099708799374418241860212545272420550537'); 41 | expect(key.p.toString(), 42 | '107414964168438393293800370153762414263170982299670223259057985688128607486167'); 43 | expect(key.q.toString(), 44 | '106792349081681004195940644966825657043901438347969492098043946341032927758743'); 45 | }); 46 | }); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /lib/utils/ufixnum.dart: -------------------------------------------------------------------------------- 1 | // This file has been copied and modified from pointy_castles package. See file 2 | // LICENSE/pointy_castle_LICENSE file for more information. 3 | 4 | library ninja.ufixnum; 5 | 6 | const mask3 = 0x07; 7 | const mask5 = 0x1F; 8 | const mask6 = 0x3F; 9 | const mask8 = 0xFF; 10 | const mask16 = 0xFFFF; 11 | const mask32 = 0xFFFFFFFF; 12 | 13 | final maskHiBits = [ 14 | 0xFFFFFFFF, 15 | 0x7FFFFFFF, 16 | 0x3FFFFFFF, 17 | 0x1FFFFFFF, 18 | 0x0FFFFFFF, 19 | 0x07FFFFFF, 20 | 0x03FFFFFF, 21 | 0x01FFFFFF, 22 | 0x00FFFFFF, 23 | 0x007FFFFF, 24 | 0x003FFFFF, 25 | 0x001FFFFF, 26 | 0x000FFFFF, 27 | 0x0007FFFF, 28 | 0x0003FFFF, 29 | 0x0001FFFF, 30 | 0x0000FFFF, 31 | 0x00007FFF, 32 | 0x00003FFF, 33 | 0x00001FFF, 34 | 0x00000FFF, 35 | 0x000007FF, 36 | 0x000003FF, 37 | 0x000001FF, 38 | 0x000000FF, 39 | 0x0000007F, 40 | 0x0000003F, 41 | 0x0000001F, 42 | 0x0000000F, 43 | 0x00000007, 44 | 0x00000003, 45 | 0x00000001, 46 | 0x00000000 47 | ]; 48 | 49 | //////////////////////////////////////////////////////////////////////////////////////////////////// 50 | // 8 bit operations 51 | // 52 | int clip8(int x) => (x & mask8); 53 | 54 | int csum8(int x, int y) => sum8(clip8(x), clip8(y)); 55 | int sum8(int x, int y) { 56 | assert((x >= 0) && (x <= mask8)); 57 | assert((y >= 0) && (y <= mask8)); 58 | return ((x + y) & mask8); 59 | } 60 | 61 | int csub8(int x, int y) => sub8(clip8(x), clip8(y)); 62 | int sub8(int x, int y) { 63 | assert((x >= 0) && (x <= mask8)); 64 | assert((y >= 0) && (y <= mask8)); 65 | return ((x - y) & mask8); 66 | } 67 | 68 | int cshiftl8(int x, int n) => shiftl8(clip8(x), n); 69 | int shiftl8(int x, int n) { 70 | assert((x >= 0) && (x <= mask8)); 71 | return ((x << (n & mask3)) & mask8); 72 | } 73 | 74 | int cshiftr8(int x, int n) => shiftr8(clip8(x), n); 75 | int shiftr8(int x, int n) { 76 | assert((x >= 0) && (x <= mask8)); 77 | return (x >> (n & mask3)); 78 | } 79 | 80 | int cneg8(int x) => neg8(clip8(x)); 81 | int neg8(int x) { 82 | assert((x >= 0) && (x <= mask8)); 83 | return (-x & mask8); 84 | } 85 | 86 | int cnot8(int x) => not8(clip8(x)); 87 | int not8(int x) { 88 | assert((x >= 0) && (x <= mask8)); 89 | return (~x & mask8); 90 | } 91 | 92 | int crotl8(int x, int n) => rotl8(clip8(x), n); 93 | int rotl8(int x, int n) { 94 | assert(n >= 0); 95 | assert((x >= 0) && (x <= mask8)); 96 | n &= mask3; 97 | return ((x << n) & mask8) | (x >> (8 - n)); 98 | } 99 | 100 | int crotr8(int x, int n) => rotr8(clip8(x), n); 101 | int rotr8(int x, int n) { 102 | assert(n >= 0); 103 | assert((x >= 0) && (x <= mask8)); 104 | n &= mask3; 105 | return ((x >> n) & mask8) | ((x << (8 - n)) & mask8); 106 | } 107 | 108 | //////////////////////////////////////////////////////////////////////////////////////////////////// 109 | // 16 bit operations 110 | // 111 | int clip16(int x) => (x & mask16); 112 | 113 | //////////////////////////////////////////////////////////////////////////////////////////////////// 114 | // 32 bit operations 115 | // 116 | int clip32(int x) => (x & mask32); 117 | 118 | int csum32(int x, int y) => sum32(clip32(x), clip32(y)); 119 | int sum32(int x, int y) { 120 | assert((x >= 0) && (x <= mask32)); 121 | assert((y >= 0) && (y <= mask32)); 122 | return ((x + y) & mask32); 123 | } 124 | 125 | int csub32(int x, int y) => sub32(clip32(x), clip32(y)); 126 | int sub32(int x, int y) { 127 | assert((x >= 0) && (x <= mask32)); 128 | assert((y >= 0) && (y <= mask32)); 129 | return ((x - y) & mask32); 130 | } 131 | 132 | int cshiftl32(int x, int n) => shiftl32(clip32(x), n); 133 | int shiftl32(int x, int n) { 134 | assert((x >= 0) && (x <= mask32)); 135 | n &= mask5; 136 | x &= maskHiBits[n]; 137 | return ((x << n) & mask32); 138 | } 139 | 140 | int cshiftr32(int x, int n) => shiftr32(clip32(x), n); 141 | int shiftr32(int x, int n) { 142 | assert((x >= 0) && (x <= mask32)); 143 | n &= mask5; 144 | return (x >> n); 145 | } 146 | 147 | int cneg32(int x) => neg32(clip32(x)); 148 | int neg32(int x) { 149 | assert((x >= 0) && (x <= mask32)); 150 | return (-x & mask32); 151 | } 152 | 153 | int cnot32(int x) => not32(clip32(x)); 154 | int not32(int x) { 155 | assert((x >= 0) && (x <= mask32)); 156 | return (~x & mask32); 157 | } 158 | 159 | int crotl32(int x, int n) => rotl32(clip32(x), n); 160 | int rotl32(int x, int n) { 161 | assert(n >= 0); 162 | assert((x >= 0) && (x <= mask32)); 163 | n &= mask5; 164 | return shiftl32(x, n) | (x >> (32 - n)); 165 | } 166 | 167 | int crotr32(int x, int n) => rotr32(clip32(x), n); 168 | int rotr32(int x, int n) { 169 | assert(n >= 0); 170 | assert((x >= 0) && (x <= mask32)); 171 | n &= mask5; 172 | return (x >> n) | shiftl32(x, (32 - n)); 173 | } 174 | -------------------------------------------------------------------------------- /lib/symmetric/aes/aes.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:ninja/block_cipher/modes/cbc.dart'; 5 | import 'package:ninja/ninja.dart'; 6 | import 'package:ninja_hex/ninja_hex.dart'; 7 | 8 | import 'engine.dart'; 9 | 10 | export 'engine.dart'; 11 | 12 | class AESKey { 13 | final Uint8List keyBytes; 14 | 15 | final Padder padder; 16 | 17 | final AESFastEncryptionEngine _encryptionEngine; 18 | 19 | final AESFastDecryptionEngine _decryptionEngine; 20 | 21 | AESKey(this.keyBytes, {this.padder = const PKCS7Padder()}) 22 | : _encryptionEngine = AESFastEncryptionEngine(keyBytes), 23 | _decryptionEngine = AESFastDecryptionEngine(keyBytes); 24 | 25 | factory AESKey.fromUTF8(String key, {Padder padder = const PKCS7Padder()}) => 26 | AESKey(Uint8List.fromList(utf8.encode(key)), padder: padder); 27 | 28 | factory AESKey.fromBase64(String key, 29 | {Padder padder = const PKCS7Padder()}) => 30 | AESKey(base64Decode(key), padder: padder); 31 | 32 | factory AESKey.fromHex(String key, {Padder padder = const PKCS7Padder()}) => 33 | AESKey(hexDecoder.convert(key), padder: padder); 34 | 35 | Uint8List encrypt(/* String | Iterable */ input) { 36 | if (input is String) { 37 | input = utf8.encode(input); 38 | } 39 | final padded = padder.pad(_encryptionEngine.blockSize, input); 40 | 41 | final encryptedBytes = _encryptionEngine.process(padded); 42 | 43 | return encryptedBytes; 44 | } 45 | 46 | String encryptToBase64(/* String | Iterable */ input) { 47 | final encryptedBytes = encrypt(input); 48 | return base64Encode(encryptedBytes); 49 | } 50 | 51 | String encryptToHex(/* String | Iterable */ input) { 52 | final encryptedBytes = encrypt(input); 53 | return hexEncoder.convert(encryptedBytes); 54 | } 55 | 56 | Iterable decrypt(/* String | Uint8List */ input) { 57 | if (input is String) { 58 | input = base64Decode(input); 59 | } 60 | 61 | final decrypted = _decryptionEngine.process(input); 62 | final unpadded = 63 | padder.unpad(_decryptionEngine.blockSize, decrypted).toList(); 64 | 65 | return unpadded; 66 | } 67 | 68 | String decryptToUtf8(/* String | Uint8List */ input) { 69 | final bytes = decrypt(input); 70 | return utf8.decode(bytes.toList()); 71 | } 72 | 73 | Uint8List encryptCbc(/* String | Uint8List */ input, 74 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 75 | return cbcBlockCipherMode.encrypt(_encryptionEngine, input, 76 | iv: iv, padder: padder); 77 | } 78 | 79 | String encryptCbcToBase64(/* String | Iterable */ input, 80 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 81 | final encryptedBytes = encryptCbc(input, iv: iv, padder: padder); 82 | return base64Encode(encryptedBytes); 83 | } 84 | 85 | String encryptCbcToHex(/* String | Iterable */ input, 86 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 87 | final encryptedBytes = encryptCbc(input, iv: iv, padder: padder); 88 | return hexEncoder.convert(encryptedBytes); 89 | } 90 | 91 | Iterable decryptCbc(/* String | Uint8List */ input, 92 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 93 | return cbcBlockCipherMode.decrypt(_decryptionEngine, input, 94 | iv: iv, padder: padder); 95 | } 96 | 97 | String decryptCbcToUtf8(/* String | Uint8List */ input, 98 | {Iterable? iv, Padder padder = const PKCS7Padder()}) { 99 | final bytes = decryptCbc(input, iv: iv, padder: padder); 100 | return utf8.decode(bytes.toList()); 101 | } 102 | 103 | Uint8List encryptCtr(/* String | Uint8List */ input, 104 | {required Uint8List iv, Padder? padder}) { 105 | return ctrBlockCipherMode.encrypt(_encryptionEngine, input, 106 | iv: iv, padder: padder); 107 | } 108 | 109 | String encryptCtrToBase64(/* String | Iterable */ input, 110 | {required Uint8List iv, Padder? padder}) { 111 | final encryptedBytes = encryptCtr(input, iv: iv, padder: padder); 112 | return base64Encode(encryptedBytes); 113 | } 114 | 115 | String encryptCtrToHex(/* String | Iterable */ input, 116 | {required Uint8List iv, Padder? padder}) { 117 | final encryptedBytes = encryptCtr(input, iv: iv, padder: padder); 118 | return hexEncoder.convert(encryptedBytes); 119 | } 120 | 121 | Iterable decryptCtr(/* String | Uint8List */ input, 122 | {required Uint8List iv, Padder? padder}) { 123 | return ctrBlockCipherMode.decrypt(_encryptionEngine, input, 124 | iv: iv, padder: padder); 125 | } 126 | 127 | String decryptCtrToUtf8(/* String | Uint8List */ input, 128 | {required Uint8List iv, Padder? padder}) { 129 | final bytes = decryptCtr(input, iv: iv, padder: padder); 130 | return utf8.decode(bytes.toList()); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /lib/hash/ripemd160.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:typed_data'; 3 | import 'package:crypto/src/hash_sink.dart'; 4 | import 'package:crypto/src/utils.dart'; 5 | import 'package:crypto/crypto.dart'; 6 | 7 | const RIPEMD160 ripemd160 = RIPEMD160._(); 8 | 9 | class RIPEMD160 extends Hash { 10 | final int blockSize = 64; 11 | 12 | const RIPEMD160._(); 13 | 14 | ByteConversionSink startChunkedConversion(Sink sink) => 15 | ByteConversionSink.from(_RIPEMD160Sink(sink)); 16 | } 17 | 18 | /// An instance of [RIPEMD160]. 19 | class _RIPEMD160Sink extends HashSink { 20 | _RIPEMD160Sink(Sink sink) : super(sink, 16, endian: Endian.little) { 21 | digest[0] = 0x67452301; 22 | digest[1] = 0xefcdab89; 23 | digest[2] = 0x98badcfe; 24 | digest[3] = 0x10325476; 25 | digest[4] = 0xc3d2e1f0; 26 | } 27 | 28 | final Uint32List digest = Uint32List(5); 29 | 30 | @override 31 | void updateHash(Uint32List msg) { 32 | assert(msg.length == 16); 33 | 34 | var a = digest[0]; 35 | var b = digest[1]; 36 | var c = digest[2]; 37 | var d = digest[3]; 38 | var e = digest[4]; 39 | 40 | var ah = a; 41 | var bh = b; 42 | var ch = c; 43 | var dh = d; 44 | var eh = e; 45 | 46 | for (var i = 0; i < 80; i++) { 47 | final t0 = (a + _f(i, b, c, d) + msg[_r[i]] + _K(i)) & mask32; 48 | final t1 = _rotl32(t0, _s[i]); 49 | var t = (t1 + e) & mask32; 50 | a = e; 51 | e = d; 52 | d = _rotl32(c, 10); 53 | c = b; 54 | b = t; 55 | t = (_rotl32( 56 | (ah + _f(79 - i, bh, ch, dh) + msg[_rh[i]] + _Kh(i)) & mask32, 57 | _sh[i]) + 58 | eh) & 59 | mask32; 60 | ah = eh; 61 | eh = dh; 62 | dh = _rotl32(ch, 10); 63 | ch = bh; 64 | bh = t; 65 | } 66 | 67 | var t = (digest[1] + c + dh) & mask32; 68 | digest[1] = (digest[2] + d + eh) & mask32; 69 | digest[2] = (digest[3] + e + ah) & mask32; 70 | digest[3] = (digest[4] + a + bh) & mask32; 71 | digest[4] = (digest[0] + b + ch) & mask32; 72 | digest[0] = t; 73 | } 74 | 75 | static const int _mask5 = 0x1F; 76 | 77 | /// rot left uint32 78 | int _rotl32(int x, int n) { 79 | return (_shiftl32(x, n)) | (x >> (32 - n) & mask32); 80 | } 81 | 82 | /// shift left uint32 83 | int _shiftl32(int x, int n) { 84 | n &= _mask5; 85 | x &= _mask32HiBits[n]; 86 | return (x << n) & mask32; 87 | } 88 | 89 | final List _mask32HiBits = [ 90 | 0xFFFFFFFF, 91 | 0x7FFFFFFF, 92 | 0x3FFFFFFF, 93 | 0x1FFFFFFF, 94 | 0x0FFFFFFF, 95 | 0x07FFFFFF, 96 | 0x03FFFFFF, 97 | 0x01FFFFFF, 98 | 0x00FFFFFF, 99 | 0x007FFFFF, 100 | 0x003FFFFF, 101 | 0x001FFFFF, 102 | 0x000FFFFF, 103 | 0x0007FFFF, 104 | 0x0003FFFF, 105 | 0x0001FFFF, 106 | 0x0000FFFF, 107 | 0x00007FFF, 108 | 0x00003FFF, 109 | 0x00001FFF, 110 | 0x00000FFF, 111 | 0x000007FF, 112 | 0x000003FF, 113 | 0x000001FF, 114 | 0x000000FF, 115 | 0x0000007F, 116 | 0x0000003F, 117 | 0x0000001F, 118 | 0x0000000F, 119 | 0x00000007, 120 | 0x00000003, 121 | 0x00000001, 122 | 0x00000000 123 | ]; 124 | } 125 | 126 | /// f 127 | int _f(int j, int x, int y, int z) { 128 | if (j <= 15) { 129 | return x ^ y ^ z; 130 | } else if (j <= 31) { 131 | return (x & y) | ((~x) & z); 132 | } else if (j <= 47) { 133 | return (x | (~y)) ^ z; 134 | } else if (j <= 63) { 135 | return (x & z) | (y & (~z)); 136 | } else { 137 | return x ^ (y | (~z)); 138 | } 139 | } 140 | 141 | /// K 142 | int _K(int j) { 143 | if (j <= 15) { 144 | return 0x00000000; 145 | } else if (j <= 31) { 146 | return 0x5a827999; 147 | } else if (j <= 47) { 148 | return 0x6ed9eba1; 149 | } else if (j <= 63) { 150 | return 0x8f1bbcdc; 151 | } else { 152 | return 0xa953fd4e; 153 | } 154 | } 155 | 156 | /// Kh 157 | int _Kh(int j) { 158 | if (j <= 15) { 159 | return 0x50a28be6; 160 | } else if (j <= 31) { 161 | return 0x5c4dd124; 162 | } else if (j <= 47) { 163 | return 0x6d703ef3; 164 | } else if (j <= 63) { 165 | return 0x7a6d76e9; 166 | } else { 167 | return 0x00000000; 168 | } 169 | } 170 | 171 | List _r = [ 172 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, // 173 | 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 174 | 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 175 | 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 176 | ]; 177 | 178 | List _rh = [ 179 | 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, // 180 | 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 181 | 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 182 | 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 183 | ]; 184 | 185 | List _s = [ 186 | 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, // 187 | 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 188 | 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 189 | 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 190 | ]; 191 | 192 | List _sh = [ 193 | 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, // 194 | 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 195 | 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 196 | 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 197 | ]; 198 | -------------------------------------------------------------------------------- /lib/padder/eme_oaep.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:crypto/crypto.dart' as crypto; 6 | import 'package:ninja/padder/mgf/mgf.dart'; 7 | import 'package:ninja/padder/padder.dart'; 8 | import 'package:ninja/utils/iterable.dart'; 9 | 10 | final sha1OaepPadder = OAEPPadder(); 11 | 12 | class OAEPPadder implements Padder, IndividualBlockPadder { 13 | final crypto.Hash hasher; 14 | 15 | final Mgf mgf; 16 | 17 | final Random random; 18 | 19 | OAEPPadder({crypto.Hash? hasher, Random? random, Mgf? mgf}) 20 | : random = random ?? Random.secure(), 21 | hasher = hasher ?? crypto.sha1, 22 | mgf = mgf ?? mgf1Sha1; 23 | 24 | void padBlock(int blockSize, Iterable block, ByteData output, 25 | {List? labelHash, /* String | List */ label}) { 26 | if (labelHash == null) { 27 | if (label == null) label = []; 28 | 29 | labelHash = hasher.convert(label).bytes; 30 | } 31 | 32 | final ps = List.generate( 33 | blockSize - block.length - (2 * labelHash.length) - 2, (_) => 0); 34 | final db = [...labelHash, ...ps, 0x01, ...block]; 35 | 36 | final seed = 37 | List.generate(labelHash.length, (_) => random.nextInt(255)); 38 | final dbMask = mgf.encode(blockSize - labelHash.length - 1, seed); 39 | final maskedDb = List.generate( 40 | blockSize - labelHash.length - 1, (i) => db[i] ^ dbMask[i]); 41 | 42 | final seedMask = mgf.encode(labelHash.length, maskedDb); 43 | final maskedSeed = 44 | List.generate(labelHash.length, (i) => seed[i] ^ seedMask[i]); 45 | 46 | int index = 0; 47 | output.setUint8(index++, 0); 48 | for (int i = 0; i < maskedSeed.length; i++) { 49 | output.setUint8(index++, maskedSeed[i]); 50 | } 51 | for (int i = 0; i < maskedDb.length; i++) { 52 | output.setUint8(index++, maskedDb[i]); 53 | } 54 | } 55 | 56 | Uint8List pad(int blockSize, Iterable input, 57 | {/* String | List */ label = const []}) { 58 | if (label is! List) { 59 | label = utf8.encode(label); 60 | } 61 | final labelHash = hasher.convert(label).bytes; 62 | 63 | int messageBlockSize = blockSize - (2 * labelHash.length) - 2; 64 | final int numMessageBlocks = (input.length / messageBlockSize).ceil(); 65 | final output = Uint8List(numMessageBlocks * blockSize); 66 | 67 | for (int i = 0; i < numMessageBlocks; i++) { 68 | Iterable block; 69 | if (i == numMessageBlocks - 1) { 70 | block = input; 71 | } else { 72 | block = input.take(messageBlockSize); 73 | input = input.skip(messageBlockSize); 74 | } 75 | padBlock( 76 | blockSize, block, output.buffer.asByteData(i * blockSize, blockSize)); 77 | } 78 | 79 | return output; 80 | } 81 | 82 | Iterable unpadBlock(int blockSize, Iterable block, 83 | {List? labelHash, /* String | List */ label}) { 84 | if (block.length != blockSize) { 85 | throw Exception('Invalid blocksize'); 86 | } 87 | 88 | if (block.elementAt(0) != 0) { 89 | throw Exception('Invalid block. First byte not 0'); 90 | } 91 | 92 | if (labelHash == null) { 93 | if (label == null) label = []; 94 | 95 | labelHash = hasher.convert(label).bytes; 96 | } 97 | 98 | final maskedSeed = block.skip(1).take(labelHash.length).toList(); 99 | final maskedDb = block.skip(1 + labelHash.length).toList(); 100 | 101 | final seedMask = mgf.encode(labelHash.length, maskedDb); 102 | final seed = List.generate( 103 | labelHash.length, (i) => seedMask[i] ^ maskedSeed[i]); 104 | 105 | final dbMask = mgf.encode(blockSize - labelHash.length - 1, seed); 106 | Iterable db = List.generate( 107 | blockSize - labelHash.length - 1, (i) => dbMask[i] ^ maskedDb[i]); 108 | 109 | final labelHashDash = db.take(labelHash.length); 110 | if (!iterableEquality.equals(labelHash, labelHashDash)) { 111 | throw Exception('Invalid block. Label hashes do not match'); 112 | } 113 | db = db.skip(labelHash.length); 114 | 115 | db = db.skipWhile((value) => value == 0); 116 | 117 | if (db.isEmpty) { 118 | throw Exception('Invalid block. No delimiter'); 119 | } 120 | 121 | if (db.first != 0x01) { 122 | throw Exception('Invalid block. Invalid delimiter'); 123 | } 124 | 125 | return db.skip(1); 126 | } 127 | 128 | Iterable unpad(int blockSize, Iterable input, 129 | {/* String | List */ label = const []}) { 130 | if (label is! List) { 131 | label = utf8.encode(label); 132 | } 133 | final labelHash = hasher.convert(label).bytes; 134 | if (input.length % blockSize != 0) { 135 | throw Exception( 136 | 'Invalid message length. Must be multiple of blockSize $blockSize. Got ${input.length}'); 137 | } 138 | 139 | int messageBlockSize = blockSize - (2 * labelHash.length) - 2; 140 | final numBlocks = input.length ~/ blockSize; 141 | 142 | final out = Uint8List(numBlocks * messageBlockSize); 143 | int outLen = 0; 144 | 145 | for (int i = 0; i < numBlocks; i++) { 146 | Iterable block = input.take(blockSize); 147 | input = input.skip(blockSize); 148 | final unpaddedMsg = unpadBlock(blockSize, block, labelHash: labelHash); 149 | out.setAll(i * messageBlockSize, unpaddedMsg); 150 | outLen += unpaddedMsg.length; 151 | } 152 | 153 | if (outLen == out.length) { 154 | return out; 155 | } 156 | 157 | return out.take(outLen); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ninja 2 | 3 | Cryptography dart library to encrypt, decrypt, sign and verify messages 4 | 5 | # RSA 6 | 7 | ## Encryption 8 | 9 | ### OAEP 10 | 11 | ```dart 12 | void main() { 13 | final privateKeyPem = ''' 14 | -----BEGIN RSA PRIVATE KEY----- 15 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 16 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 17 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 18 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 19 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 20 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 21 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 22 | -----END RSA PRIVATE KEY-----'''; 23 | 24 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 25 | final publicKey = privateKey.toPublicKey; 26 | 27 | String encrypted = publicKey.encryptOaepToBase64( 28 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 29 | print(encrypted); 30 | String decrypted = privateKey.decryptOaepToUtf8(encrypted); 31 | print(decrypted); 32 | } 33 | ``` 34 | 35 | ### pkcs1v15 36 | 37 | ```dart 38 | main() { 39 | final privateKeyPem = ''' 40 | -----BEGIN RSA PRIVATE KEY----- 41 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 42 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 43 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 44 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 45 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 46 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 47 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 48 | -----END RSA PRIVATE KEY-----'''; 49 | 50 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 51 | final publicKey = privateKey.toPublicKey; 52 | 53 | String encrypted = publicKey.encryptToBase64( 54 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit...'); 55 | print(encrypted); 56 | String decrypted = privateKey.decryptToUtf8(encrypted); 57 | print(decrypted); 58 | } 59 | ``` 60 | 61 | ## Signature 62 | 63 | ### RSASSA-PSS 64 | 65 | ```dart 66 | void main() { 67 | final privateKeyPem = ''' 68 | -----BEGIN RSA PRIVATE KEY----- 69 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 70 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 71 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 72 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 73 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 74 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 75 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 76 | -----END RSA PRIVATE KEY-----'''; 77 | 78 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 79 | final publicKey = privateKey.toPublicKey; 80 | 81 | final message = 'abcdefghijklmnopqrstuvwxyz\n'; 82 | 83 | final signature = privateKey.signPssToBase64(message); 84 | print(signature); 85 | 86 | print(publicKey.verifySsaPss(signature, message)); 87 | 88 | final verifier = RsaSsaPssVerifier(saltLength: 10); 89 | print(verifier.extractSalt(publicKey, signature)); 90 | } 91 | ``` 92 | 93 | ### RSASSA-PKCS1-V1_5 94 | 95 | ```dart 96 | void main() { 97 | final privateKeyPem = ''' 98 | -----BEGIN RSA PRIVATE KEY----- 99 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 100 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 101 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 102 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 103 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 104 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 105 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 106 | -----END RSA PRIVATE KEY-----'''; 107 | 108 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPem); 109 | final publicKey = privateKey.toPublicKey; 110 | 111 | final message = 'abcdefghijklmnopqrstuvwxyz\n'; 112 | 113 | final signature = privateKey.signSsaPkcs1v15ToBase64(message); 114 | print(signature); 115 | 116 | print(publicKey.verifySsaPkcs1v15(signature, message)); 117 | } 118 | ``` 119 | 120 | ## Keys 121 | 122 | ### Generate key 123 | 124 | ```dart 125 | void main() { 126 | final privateKey = RSAPrivateKey.generate(1024); 127 | print(privateKey.p); 128 | print(privateKey.q); 129 | print(privateKey.n.bitLength); 130 | } 131 | ``` 132 | 133 | ## Load key from PEM 134 | 135 | ```dart 136 | final publicKeyPkcs1 = ''' 137 | -----BEGIN RSA PUBLIC KEY----- 138 | MEgCQQDL+0XmsJ8a9A32DdyGW2+Yof1yRni1g7+1roU5Ynv/3Nkw18P5lvdeFRcq 139 | AX8UMQHs0o/GKbgA4k8Kg2Zdd8CjAgMBAAE= 140 | -----END RSA PUBLIC KEY-----'''; 141 | 142 | final publicKeyPkcs8 = ''' 143 | -----BEGIN PUBLIC KEY----- 144 | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWD 145 | v7WuhTlie//c2TDXw/mW914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQ== 146 | -----END PUBLIC KEY-----'''; 147 | 148 | final privateKeyPkcs1 = ''' 149 | -----BEGIN RSA PRIVATE KEY----- 150 | MIIBOwIBAAJBAMv7Reawnxr0DfYN3IZbb5ih/XJGeLWDv7WuhTlie//c2TDXw/mW 151 | 914VFyoBfxQxAezSj8YpuADiTwqDZl13wKMCAwEAAQJAYaTrFT8/KpvhgwOnqPlk 152 | NmB0/psVdW6X+tSMGag3S4cFid3nLkN384N6tZ+na1VWNkLy32Ndpxo6pQq4NSAb 153 | YQIhAPNlJsV+Snpg+JftgviV5+jOKY03bx29GsZF+umN6hD/AiEA1ouXAO2mVGRk 154 | BuoGXe3o/d5AOXj41vTB8D6IUGu8bF0CIQC6zah7LRmGYYSKPk0l8w+hmxFDBAex 155 | IGE7SZxwwm2iCwIhAInnDbe2CbyjDrx2/oKvopxTmDqY7HHWvzX6K8pthZ6tAiAw 156 | w+DJoSx81QQpD8gY/BXjovadVtVROALaFFvdmN64sw== 157 | -----END RSA PRIVATE KEY-----'''; 158 | 159 | final privateKeyPkcs8 = ''' 160 | -----BEGIN PRIVATE KEY----- 161 | MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAy/tF5rCfGvQN9g3c 162 | hltvmKH9ckZ4tYO/ta6FOWJ7/9zZMNfD+Zb3XhUXKgF/FDEB7NKPxim4AOJPCoNm 163 | XXfAowIDAQABAkBhpOsVPz8qm+GDA6eo+WQ2YHT+mxV1bpf61IwZqDdLhwWJ3ecu 164 | Q3fzg3q1n6drVVY2QvLfY12nGjqlCrg1IBthAiEA82UmxX5KemD4l+2C+JXn6M4p 165 | jTdvHb0axkX66Y3qEP8CIQDWi5cA7aZUZGQG6gZd7ej93kA5ePjW9MHwPohQa7xs 166 | XQIhALrNqHstGYZhhIo+TSXzD6GbEUMEB7EgYTtJnHDCbaILAiEAiecNt7YJvKMO 167 | vHb+gq+inFOYOpjscda/Nforym2Fnq0CIDDD4MmhLHzVBCkPyBj8FeOi9p1W1VE4 168 | AtoUW92Y3riz 169 | -----END PRIVATE KEY-----'''; 170 | 171 | void pkcs1() { 172 | final publicKey = RSAPublicKey.fromPEM(publicKeyPkcs1); 173 | print(publicKey.toPem(toPkcs1: true)); 174 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPkcs1); 175 | print(privateKey.toPem()); 176 | print(privateKey.toPem(toPkcs1: false)); 177 | } 178 | 179 | void pkcs8() { 180 | final publicKey = RSAPublicKey.fromPEM(publicKeyPkcs8); 181 | print(publicKey.toPem()); 182 | final privateKey = RSAPrivateKey.fromPEM(privateKeyPkcs8); 183 | print(privateKey.toPem(toPkcs1: false)); 184 | } 185 | ``` 186 | 187 | # AES 188 | 189 | ## Encryption 190 | 191 | ```dart 192 | main() { 193 | final aes = AESKey(Uint8List.fromList(List.generate(16, (i) => i))); 194 | String encoded = aes.encryptToBase64('Dart'); 195 | print(encoded); 196 | String decoded = aes.decryptToUtf8(encoded); 197 | print(decoded); 198 | } 199 | ``` 200 | 201 | # TODO 202 | 203 | + [ ] AES key derivation 204 | + [ ] More block cipher modes 205 | + [ ] CFB 206 | + [ ] OFB 207 | + [ ] GCM 208 | + [ ] ECB 209 | + [ ] PCBC 210 | + [ ] Curve based cryptography -------------------------------------------------------------------------------- /lib/asymmetric/rsa/signer/emsa_pss.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:crypto/crypto.dart'; 6 | import 'package:ninja/asymmetric/rsa/rsa.dart'; 7 | import 'package:ninja/asymmetric/rsa/signer/signer.dart'; 8 | import 'package:ninja/padder/mgf/mgf.dart'; 9 | import 'package:ninja/utils/big_int.dart'; 10 | import 'package:ninja/utils/iterable.dart'; 11 | import 'package:ninja/utils/listops.dart'; 12 | 13 | class RsaSsaPssSigner implements RsaSigner { 14 | final Mgf mgf; 15 | 16 | final Hash hasher; 17 | 18 | final int saltLength; 19 | 20 | final Random saltGenerator; 21 | 22 | RsaSsaPssSigner( 23 | {Mgf? mgf, Hash? hasher, this.saltLength = 0, Random? saltGenerator}) 24 | : mgf = mgf ?? mgf1Sha256, 25 | hasher = hasher ?? sha256, 26 | saltGenerator = saltGenerator ?? Random.secure(); 27 | 28 | List sign(RSAPrivateKey key, /* String | List | BigInt */ msg, 29 | {List? salt}) { 30 | int blockSize = key.blockSize; 31 | int emBits = key.bitSize - 1; 32 | 33 | List msgBytes; 34 | if (msg is List) { 35 | msgBytes = msg; 36 | } else if (msg is Iterable) { 37 | msgBytes = msg.toList(); 38 | } else if (msg is String) { 39 | msgBytes = utf8.encode(msg); 40 | } else if (msg is BigInt) { 41 | msgBytes = bigIntToBytes(msg); 42 | } else { 43 | throw Exception('invalid message type'); 44 | } 45 | 46 | final mHash = hasher.convert(msgBytes).bytes; 47 | final hashLength = mHash.length; 48 | 49 | if (emBits < (8 * (hashLength + saltLength) + 9)) { 50 | throw Exception('emBits too small'); 51 | } 52 | 53 | if (blockSize < hashLength + saltLength + 2) { 54 | throw Exception('encoding error. blockSize too small'); 55 | } 56 | 57 | if (salt == null) { 58 | salt = 59 | List.generate(saltLength, (index) => saltGenerator.nextInt(256)); 60 | } else { 61 | if (salt.length != saltLength) { 62 | throw Exception('invalid salt. must be of length $saltLength'); 63 | } 64 | } 65 | 66 | final mDash = [ 67 | ...List.filled(8, 0), 68 | ...mHash, 69 | ...salt, 70 | ]; 71 | 72 | final h = hasher.convert(mDash).bytes; 73 | 74 | final ps = List.filled(blockSize - saltLength - hashLength - 2, 0); 75 | 76 | final db = [ 77 | ...ps, 78 | 0x01, 79 | ...salt, 80 | ]; 81 | 82 | final dbMask = mgf.encode(blockSize - hashLength - 1, h); 83 | 84 | final maskedDb = ListOps.xor(db, dbMask); 85 | 86 | final em = Uint8List.fromList([ 87 | ...maskedDb, 88 | ...h, 89 | 0xbc, 90 | ]); 91 | 92 | int emDiff = (8 * blockSize) - (emBits); 93 | if (emDiff < 0) { 94 | throw Exception(); 95 | } else if (emDiff > 7) { 96 | throw Exception(); 97 | } 98 | emDiff = 8 - emDiff; 99 | 100 | em[0] &= (1 << emDiff) - 1; 101 | 102 | return key.engine.signBlock(em); 103 | } 104 | 105 | String signToBase64(RSAPrivateKey key, /* String | List | BigInt */ msg, 106 | {List? salt}) { 107 | final bytes = sign(key, msg, salt: salt); 108 | return base64Encode(bytes); 109 | } 110 | } 111 | 112 | class RsaSsaPssVerifier implements RsaVerifier { 113 | final Mgf mgf; 114 | 115 | final Hash hasher; 116 | 117 | final int saltLength; 118 | 119 | RsaSsaPssVerifier({Mgf? mgf, Hash? hasher, this.saltLength = 0}) 120 | : mgf = mgf ?? mgf1Sha256, 121 | hasher = hasher ?? sha256; 122 | 123 | bool verify( 124 | RSAPublicKey key, 125 | /* String | List | BigInt */ signature, 126 | /* String | List | BigInt */ msg) { 127 | int emBits = key.bitSize - 1; 128 | 129 | List msgBytes; 130 | if (msg is List) { 131 | msgBytes = msg; 132 | } else if (msg is Iterable) { 133 | msgBytes = msg.toList(); 134 | } else if (msg is String) { 135 | msgBytes = utf8.encode(msg); 136 | } else if (msg is BigInt) { 137 | msgBytes = bigIntToBytes(msg); 138 | } else { 139 | throw Exception('Unknown type'); 140 | } 141 | 142 | final mHash = hasher.convert(msgBytes).bytes; 143 | final hashLength = mHash.length; 144 | 145 | if (emBits < (8 * (hashLength + saltLength) + 9)) { 146 | throw Exception('emBits too small'); 147 | } 148 | 149 | final em = key.engine.unsign(signature); 150 | 151 | if (em.length < hashLength + saltLength + 2) { 152 | throw Exception('inconsistent. encoded message length small'); 153 | } 154 | 155 | if (em.last != 0xbc) { 156 | throw Exception('inconsistent. bc octet not found in encoded message'); 157 | } 158 | 159 | final maskedDb = em.take(key.blockSize - hashLength - 1); 160 | final h = em.skip(key.blockSize - hashLength - 1).take(hashLength); 161 | 162 | final dbMask = mgf.encode(maskedDb.length, h); 163 | 164 | final db = ListOps.xor(maskedDb, dbMask); 165 | 166 | int emDiff = (8 * key.blockSize) - (emBits); 167 | if (emDiff < 0) { 168 | throw Exception(); 169 | } else if (emDiff > 7) { 170 | throw Exception(); 171 | } 172 | 173 | db[0] &= (1 << emDiff) - 1; 174 | 175 | final ps = db.take(key.blockSize - hashLength - saltLength - 2); 176 | if (ps.any((element) => element != 0)) { 177 | throw Exception('inconsistent. invalid ps'); 178 | } 179 | if (db.skip(key.blockSize - hashLength - saltLength - 2).first != 0x01) { 180 | throw Exception('inconsistents'); 181 | } 182 | 183 | final salt = db.skip(key.blockSize - hashLength - saltLength - 1); 184 | 185 | final mDash = [ 186 | ...List.filled(8, 0), 187 | ...mHash, 188 | ...salt, 189 | ]; 190 | 191 | final hDash = hasher.convert(mDash).bytes; 192 | 193 | return iterableEquality.equals(h, hDash); 194 | } 195 | 196 | String extractSalt( 197 | RSAPublicKey key, 198 | /* String | List | BigInt */ signature) { 199 | final hashLength = hasher.convert([0]).bytes.length; 200 | 201 | final em = key.engine.unsign(signature); 202 | 203 | if (em.length < hashLength + saltLength + 2) { 204 | throw Exception('inconsistent. encoded message length small'); 205 | } 206 | 207 | if (em.last != 0xbc) { 208 | throw Exception('inconsistent. bc octet not found in encoded message'); 209 | } 210 | 211 | final maskedDb = em.take(key.blockSize - hashLength - 1); 212 | final h = em.skip(key.blockSize - hashLength - 1).take(hashLength); 213 | 214 | final dbMask = mgf.encode(maskedDb.length, h); 215 | 216 | final db = ListOps.xor(maskedDb, dbMask); 217 | 218 | int emDiff = (8 * key.blockSize) - key.bitSize; 219 | if (emDiff < 0) { 220 | throw Exception(); 221 | } else if (emDiff > 7) { 222 | throw Exception(); 223 | } 224 | 225 | db[0] &= (1 << emDiff) - 1; 226 | 227 | final ps = db.take(key.blockSize - hashLength - saltLength - 2); 228 | if (ps.any((element) => element != 0)) { 229 | throw Exception('inconsistent. invalid ps'); 230 | } 231 | if (db.skip(key.blockSize - hashLength - saltLength - 2).first != 0x01) { 232 | throw Exception('inconsistent'); 233 | } 234 | 235 | final salt = db.skip(key.blockSize - hashLength - saltLength - 1).toList(); 236 | 237 | return base64Encode(salt); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /lib/asymmetric/rsa/rsa.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:math'; 3 | import 'dart:typed_data'; 4 | 5 | import 'package:crypto/crypto.dart'; 6 | import 'package:ninja/asymmetric/rsa/signer/emsa_pss.dart'; 7 | import 'package:ninja/padder/mgf/mgf.dart'; 8 | import 'package:ninja_prime/ninja_prime.dart'; 9 | 10 | import 'package:ninja/asymmetric/rsa/encoder/emsaPkcs1v15.dart'; 11 | import 'package:ninja/asymmetric/rsa/engine/decrypter.dart'; 12 | import 'package:ninja/asymmetric/rsa/engine/encrypter.dart'; 13 | import 'package:ninja/asymmetric/rsa/signer/rsassa_pks1_v15.dart'; 14 | import 'package:ninja_asn1/ninja_asn1.dart'; 15 | import 'package:ninja_pem/ninja_pem.dart'; 16 | import 'package:ninja/ninja.dart'; 17 | import 'package:ninja_hex/ninja_hex.dart'; 18 | 19 | export 'signer/signer.dart'; 20 | 21 | /// Public key for RSA encryption 22 | class RSAPublicKey { 23 | RSAPublicKey(this.n, this.e) { 24 | _engine = RSAEncryptionEngine(this); 25 | } 26 | 27 | factory RSAPublicKey.fromASN1(/* String | Iterable */ input, 28 | {bool fromPkcs1 = false}) { 29 | if (!fromPkcs1) { 30 | final seq = ASN1Sequence.decode(input); 31 | if (seq.children.length != 2) { 32 | throw Exception('Invalid structure'); 33 | } 34 | 35 | if (seq.children[1] is! ASN1BitString) { 36 | throw Exception('Invalid structure'); 37 | } 38 | 39 | final bitString = seq.children[1] as ASN1BitString; 40 | 41 | if (bitString.unusedBits != 0) { 42 | throw Exception('Invalid structure'); 43 | } 44 | 45 | if (seq.children[0] is! ASN1Sequence) { 46 | throw Exception('Invalid structure'); 47 | } 48 | 49 | final algIdentifier = seq.children[0] as ASN1Sequence; 50 | 51 | if (algIdentifier.children.isEmpty) { 52 | throw Exception('Invalid structure'); 53 | } 54 | 55 | if (algIdentifier.children.first is! ASN1ObjectIdentifier) { 56 | throw Exception('Invalid structure'); 57 | } 58 | 59 | final ASN1ObjectIdentifier identifer = 60 | algIdentifier.children.first as ASN1ObjectIdentifier; 61 | 62 | if (identifer.objectIdentifierAsString != '1.2.840.113549.1.1.1') { 63 | throw Exception('Invalid structure'); 64 | } 65 | 66 | input = bitString.bitString; 67 | } 68 | 69 | final seq = ASN1Sequence.decode(input); 70 | 71 | if (seq.children.length != 2) { 72 | throw Exception('Invalid structure'); 73 | } 74 | 75 | if (seq.children.any((e) => e is! ASN1Integer)) { 76 | throw Exception('Invalid structure'); 77 | } 78 | 79 | final numbers = 80 | seq.children.cast().map((e) => e.value).toList(); 81 | 82 | return RSAPublicKey(numbers[0], numbers[1]); 83 | } 84 | 85 | factory RSAPublicKey.fromPEM(String input) { 86 | final pem = PemPart.decodeLabelled(input, ['RSA PUBLIC KEY', 'PUBLIC KEY']); 87 | return RSAPublicKey.fromASN1(pem.data, 88 | fromPkcs1: pem.label == 'RSA PUBLIC KEY'); 89 | } 90 | 91 | /// Modulus 92 | final BigInt n; 93 | 94 | /// Public exponent 95 | final BigInt e; 96 | 97 | RSAEncryptionEngine? _engine; 98 | 99 | RSAEncryptionEngine get engine => _engine!; 100 | 101 | int get blockSize => engine.blockSize; 102 | 103 | int get bitSize => n.bitLength; 104 | 105 | Iterable encrypt(/* String | Iterable */ input, {Padder? padder}) { 106 | Iterable inputBytes; 107 | if (input is String) { 108 | inputBytes = utf8.encode(input); 109 | } else if (input is Iterable) { 110 | inputBytes = input; 111 | } else { 112 | throw ArgumentError('Should be String or List'); 113 | } 114 | if (padder != null) { 115 | inputBytes = padder.pad(blockSize, inputBytes); 116 | } 117 | return engine.process(inputBytes); 118 | } 119 | 120 | String encryptToBase64(/* String | Iterable */ input, {Padder? padder}) { 121 | final bytes = encrypt(input, padder: padder); 122 | return base64Encode(bytes.toList()); 123 | } 124 | 125 | String encryptToHex(/* String | Iterable */ input, {Padder? padder}) { 126 | return hexEncode(encrypt(input, padder: padder)); 127 | } 128 | 129 | Iterable encryptPkcs1v15(/* String | Iterable */ input, 130 | {Random? rand}) { 131 | return encrypt(input, padder: EmePkcs1v15Encoder(rand: rand)); 132 | } 133 | 134 | String encryptPkcs1v15ToBase64(/* String | Iterable */ input, 135 | {Random? rand}) { 136 | return encryptToBase64(input, padder: EmePkcs1v15Encoder(rand: rand)); 137 | } 138 | 139 | String encryptPkcs1v15ToHex(/* String | Iterable */ input, 140 | {Random? rand}) { 141 | return encryptToHex(input, padder: EmePkcs1v15Encoder(rand: rand)); 142 | } 143 | 144 | Iterable encryptOaep(/* String | Iterable */ input, 145 | {OAEPPadder? oaepPadder}) { 146 | return encrypt(input, padder: oaepPadder ?? sha1OaepPadder); 147 | } 148 | 149 | String encryptOaepToBase64(/* String | Iterable */ input, 150 | {OAEPPadder? oaepPadder}) { 151 | return encryptToBase64(input, padder: oaepPadder ?? sha1OaepPadder); 152 | } 153 | 154 | String encryptOaepToHex(/* String | Iterable */ input, 155 | {OAEPPadder? oaepPadder}) { 156 | return encryptToHex(input, padder: oaepPadder ?? sha1OaepPadder); 157 | } 158 | 159 | bool verifySsaPkcs1v15(/* String | List | BigInt */ signature, 160 | final /* String | List | BigInt */ msg, 161 | {EmsaHasher? hasher}) { 162 | return RsassaPkcs1v15Verifier(hasher: hasher).verify(this, signature, msg); 163 | } 164 | 165 | bool verifySsaPss(/* String | List | BigInt */ signature, 166 | final /* String | List | BigInt */ msg, 167 | {Mgf? mgf, 168 | Hash? hasher, 169 | int saltLength = 10, 170 | RsaSsaPssVerifier? verifier}) { 171 | verifier ??= 172 | RsaSsaPssVerifier(mgf: mgf, hasher: hasher, saltLength: saltLength); 173 | return verifier.verify(this, signature, msg); 174 | } 175 | 176 | String toASN1({bool toPkcs1 = false, Iterable? parameters}) { 177 | final encoded = ASN1Sequence([ASN1Integer(n), ASN1Integer(e)]).encode(); 178 | if (toPkcs1) { 179 | return base64Encode(encoded); 180 | } 181 | return base64Encode(ASN1Sequence([ 182 | ASN1Sequence([ 183 | ASN1ObjectIdentifier.fromString('1.2.840.113549.1.1.1'), 184 | ...(parameters != null && parameters.isNotEmpty 185 | ? parameters 186 | : [ASN1Null()]), 187 | ]), 188 | ASN1BitString(encoded) 189 | ]).encode()); 190 | } 191 | 192 | String toPem({bool toPkcs1 = false}) { 193 | String asn1 = toASN1(toPkcs1: toPkcs1); 194 | String label = toPkcs1 ? 'RSA PUBLIC KEY' : 'PUBLIC KEY'; 195 | return PemPart(label, asn1).toString(); 196 | } 197 | 198 | String toString() => 'RSAPublicKey(n: $n, e: $e)'; 199 | } 200 | 201 | /// Private key for RSA encryption 202 | class RSAPrivateKey { 203 | RSAPrivateKey(this.n, this.e, this.d, this.p, this.q) { 204 | _engine = RSADecryptionEngine(this); 205 | } 206 | 207 | factory RSAPrivateKey.fromPrimaries(BigInt p, BigInt q, 208 | {BigInt? publicExponent}) { 209 | publicExponent ??= BigInt.from(0x01001); 210 | 211 | final n = p * q; 212 | 213 | BigInt d = publicExponent.modInverse((p - BigInt.one) * (q - BigInt.one)); 214 | 215 | return RSAPrivateKey(n, publicExponent, d, p, q); 216 | } 217 | 218 | factory RSAPrivateKey.generate(int keySize, {BigInt? publicExponent}) { 219 | publicExponent ??= BigInt.from(0x01001); 220 | 221 | BigInt p; 222 | while (true) { 223 | p = randomPrimeBigInt(keySize ~/ 2); 224 | 225 | if (p % publicExponent == BigInt.one) { 226 | continue; 227 | } 228 | 229 | if (publicExponent.gcd(p - BigInt.one) == BigInt.one) { 230 | break; 231 | } 232 | } 233 | 234 | BigInt q; 235 | BigInt n; 236 | int qBitLength = keySize - p.bitLength; 237 | while (true) { 238 | q = randomPrimeBigInt(qBitLength); 239 | 240 | if (p == q) { 241 | continue; 242 | } 243 | 244 | if (q % publicExponent == BigInt.one) { 245 | continue; 246 | } 247 | 248 | if (publicExponent.gcd(q - BigInt.one) != BigInt.one) { 249 | continue; 250 | } 251 | 252 | n = p * q; 253 | final nBitlength = n.bitLength; 254 | if (nBitlength != keySize) { 255 | continue; 256 | } 257 | 258 | if (p < q) { 259 | BigInt tmp = p; 260 | p = q; 261 | q = tmp; 262 | } 263 | 264 | return RSAPrivateKey.fromPrimaries(p, q, publicExponent: publicExponent); 265 | } 266 | } 267 | 268 | factory RSAPrivateKey.fromASN1(dynamic /* String | Iterable */ input, 269 | {bool fromPkcs1 = true}) { 270 | if (!fromPkcs1) { 271 | final seq = ASN1Sequence.decode(input); 272 | if (seq.children.length != 3) { 273 | throw Exception('Invalid structure'); 274 | } 275 | 276 | if (seq.children[2] is! ASN1OctetString) { 277 | throw Exception('Invalid structure'); 278 | } 279 | 280 | final bitString = seq.children[2] as ASN1OctetString; 281 | 282 | if (seq.children[1] is! ASN1Sequence) { 283 | throw Exception('Invalid structure'); 284 | } 285 | 286 | final algIdentifier = seq.children[1] as ASN1Sequence; 287 | 288 | if (algIdentifier.children.isEmpty) { 289 | throw Exception('Invalid structure'); 290 | } 291 | 292 | if (algIdentifier.children.first is! ASN1ObjectIdentifier) { 293 | throw Exception('Invalid structure'); 294 | } 295 | 296 | final ASN1ObjectIdentifier identifer = 297 | algIdentifier.children.first as ASN1ObjectIdentifier; 298 | 299 | if (identifer.objectIdentifierAsString != '1.2.840.113549.1.1.1') { 300 | throw Exception('Invalid structure'); 301 | } 302 | 303 | input = bitString.value; 304 | } 305 | 306 | final seq = ASN1Sequence.decode(input); 307 | 308 | if (seq.children.length < 9) { 309 | throw Exception('Invalid structure'); 310 | } 311 | 312 | final relevant = seq.children.skip(1).take(5); 313 | if (relevant.any((el) => el is! ASN1Integer)) { 314 | throw Exception('Invalid structure'); 315 | } 316 | 317 | final bigInts = relevant.map((e) => (e as ASN1Integer).value).toList(); 318 | return RSAPrivateKey( 319 | bigInts[0], bigInts[1], bigInts[2], bigInts[3], bigInts[4]); 320 | } 321 | 322 | factory RSAPrivateKey.fromPEM(String input) { 323 | final pem = 324 | PemPart.decodeLabelled(input, ['RSA PRIVATE KEY', 'PRIVATE KEY']); 325 | return RSAPrivateKey.fromASN1(pem.data, 326 | fromPkcs1: pem.label == 'RSA PRIVATE KEY'); 327 | } 328 | 329 | /// Modulus 330 | final BigInt n; 331 | 332 | /// Public exponent 333 | final BigInt e; 334 | 335 | /// Private exponent 336 | final BigInt d; 337 | 338 | /// Prime p 339 | final BigInt p; 340 | 341 | /// Prime q 342 | final BigInt q; 343 | 344 | RSADecryptionEngine? _engine; 345 | 346 | RSADecryptionEngine get engine => _engine!; 347 | 348 | int get blockSize => engine.blockSize; 349 | 350 | int get bitSize => n.bitLength; 351 | 352 | Iterable decrypt(/* String | List */ input, 353 | {Padder? padder, bool raw = false}) { 354 | Uint8List inputBytes; 355 | if (input is String) { 356 | inputBytes = base64Decode(input); 357 | } else if (input is Uint8List) { 358 | inputBytes = input; 359 | } else if (input is List) { 360 | inputBytes = Uint8List.fromList(input); 361 | } else { 362 | throw ArgumentError('Should be String or List'); 363 | } 364 | Iterable unpadded = engine.process(inputBytes, dontPadLastBlock: raw); 365 | if (padder == null) { 366 | return unpadded; 367 | } 368 | return padder.unpad(blockSize, unpadded); 369 | } 370 | 371 | String decryptToUtf8(/* String | List */ input, 372 | {Padder? padder, bool raw = false}) { 373 | return utf8.decode(decrypt(input, padder: padder, raw: raw).toList()); 374 | } 375 | 376 | Iterable decryptPkcs1v15(/* String | List */ input) { 377 | return decrypt(input, padder: EmePkcs1v15Encoder()); 378 | } 379 | 380 | String decryptPkcs1v15ToUtf8(/* String | List */ input) { 381 | return decryptToUtf8(input, padder: EmePkcs1v15Encoder()); 382 | } 383 | 384 | Iterable decryptOaep(/* String | List */ input, 385 | {OAEPPadder? oaepPadder}) { 386 | return decrypt(input, padder: oaepPadder ?? sha1OaepPadder); 387 | } 388 | 389 | String decryptOaepToUtf8(/* String | List */ input, 390 | {OAEPPadder? oaepPadder}) { 391 | return decryptToUtf8(input, padder: oaepPadder ?? sha1OaepPadder); 392 | } 393 | 394 | List signSsaPkcs1v15(final /* String | List | BigInt */ msg, 395 | {EmsaHasher? hasher}) { 396 | return RsassaPkcs1v15Signer(hasher: hasher).sign(this, msg); 397 | } 398 | 399 | String signSsaPkcs1v15ToBase64(/* String | List | BigInt */ msg, 400 | {EmsaHasher? hasher}) { 401 | return RsassaPkcs1v15Signer(hasher: hasher).signToBase64(this, msg); 402 | } 403 | 404 | Iterable signPss(final /* String | List | BigInt */ msg, 405 | {Mgf? mgf, 406 | Hash? hasher, 407 | int saltLength = 10, 408 | Random? saltGenerator, 409 | RsaSsaPssSigner? signer}) { 410 | signer ??= RsaSsaPssSigner( 411 | mgf: mgf, 412 | hasher: hasher, 413 | saltLength: saltLength, 414 | saltGenerator: saltGenerator); 415 | return signer.sign(this, msg); 416 | } 417 | 418 | String signPssToBase64(final /* String | List | BigInt */ msg, 419 | {Mgf? mgf, 420 | Hash? hasher, 421 | int saltLength = 10, 422 | Random? saltGenerator, 423 | RsaSsaPssSigner? signer}) { 424 | signer ??= RsaSsaPssSigner( 425 | mgf: mgf, 426 | hasher: hasher, 427 | saltLength: saltLength, 428 | saltGenerator: saltGenerator); 429 | return signer.signToBase64(this, msg); 430 | } 431 | 432 | RSAPublicKey get toPublicKey => RSAPublicKey(n, e); 433 | 434 | String toASN1({bool toPkcs1 = true, Iterable? parameters}) { 435 | final dModP = d % (p - BigInt.from(1)); 436 | final dModQ = d % (q - BigInt.from(1)); 437 | final coefficient = q.modInverse(p); 438 | final encoded = ASN1Sequence([ 439 | ASN1Integer.fromNum(0), 440 | ASN1Integer(n), 441 | ASN1Integer(e), 442 | ASN1Integer(d), 443 | ASN1Integer(p), 444 | ASN1Integer(q), 445 | ASN1Integer(dModP), 446 | ASN1Integer(dModQ), 447 | ASN1Integer(coefficient), 448 | ]).encode(); 449 | if (toPkcs1) { 450 | return base64Encode(encoded); 451 | } 452 | return base64Encode(ASN1Sequence([ 453 | ASN1Integer.fromNum(0), 454 | ASN1Sequence([ 455 | ASN1ObjectIdentifier.fromString('1.2.840.113549.1.1.1'), 456 | ...(parameters != null && parameters.isNotEmpty 457 | ? parameters 458 | : [ASN1Null()]), 459 | ]), 460 | ASN1OctetString(encoded) 461 | ]).encode()); 462 | } 463 | 464 | String toPem({bool toPkcs1 = true}) { 465 | String asn1 = toASN1(toPkcs1: toPkcs1); 466 | String label = toPkcs1 ? 'RSA PRIVATE KEY' : 'PRIVATE KEY'; 467 | return PemPart(label, asn1).toString(); 468 | } 469 | 470 | String toString() => 'RSAPrivateKey(n: $n, e: $e, d: $d, p: $p, q: $q)'; 471 | } 472 | -------------------------------------------------------------------------------- /LICENSES/pointy_castles.LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The Pointy Castle library is dually licensed under "GNU LESSER GENERAL PUBLIC LICENSE 3.0" and 3 | "Mozilla Public License 2.0". 4 | 5 | Initially the project was just released under LGPL 3.0 but due to the way dart2js works, it was 6 | necessary to license it under MPL 2.0. This is because LGPL 3.0 forces developers of closed source 7 | applications to provide some way to let the final user change the LGPL library by a different 8 | implementation which is impossible due to dart2js not supporting dynamic linking. 9 | 10 | With MPL 2.0 the library can be compiled with dart2js and mixed with closed source without violating 11 | the license. The good thing is that, even with that possibility, modifications to any source file 12 | belonging to the Pointy Castle library must be made available under MPL 2.0 and contributed to the 13 | original project so they will still remain free. 14 | 15 | Following are the contents of both licenses. 16 | 17 | ==================================================================================================== 18 | ==================================================================================================== 19 | ==================================================================================================== 20 | 21 | GNU LESSER GENERAL PUBLIC LICENSE 22 | Version 3, 29 June 2007 23 | 24 | Copyright (C) 2007 Free Software Foundation, Inc. 25 | Everyone is permitted to copy and distribute verbatim copies 26 | of this license document, but changing it is not allowed. 27 | 28 | 29 | This version of the GNU Lesser General Public License incorporates 30 | the terms and conditions of version 3 of the GNU General Public 31 | License, supplemented by the additional permissions listed below. 32 | 33 | 0. Additional Definitions. 34 | 35 | As used herein, "this License" refers to version 3 of the GNU Lesser 36 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 37 | General Public License. 38 | 39 | "The Library" refers to a covered work governed by this License, 40 | other than an Application or a Combined Work as defined below. 41 | 42 | An "Application" is any work that makes use of an interface provided 43 | by the Library, but which is not otherwise based on the Library. 44 | Defining a subclass of a class defined by the Library is deemed a mode 45 | of using an interface provided by the Library. 46 | 47 | A "Combined Work" is a work produced by combining or linking an 48 | Application with the Library. The particular version of the Library 49 | with which the Combined Work was made is also called the "Linked 50 | Version". 51 | 52 | The "Minimal Corresponding Source" for a Combined Work means the 53 | Corresponding Source for the Combined Work, excluding any source code 54 | for portions of the Combined Work that, considered in isolation, are 55 | based on the Application, and not on the Linked Version. 56 | 57 | The "Corresponding Application Code" for a Combined Work means the 58 | object code and/or source code for the Application, including any data 59 | and utility programs needed for reproducing the Combined Work from the 60 | Application, but excluding the System Libraries of the Combined Work. 61 | 62 | 1. Exception to Section 3 of the GNU GPL. 63 | 64 | You may convey a covered work under sections 3 and 4 of this License 65 | without being bound by section 3 of the GNU GPL. 66 | 67 | 2. Conveying Modified Versions. 68 | 69 | If you modify a copy of the Library, and, in your modifications, a 70 | facility refers to a function or data to be supplied by an Application 71 | that uses the facility (other than as an argument passed when the 72 | facility is invoked), then you may convey a copy of the modified 73 | version: 74 | 75 | a) under this License, provided that you make a good faith effort to 76 | ensure that, in the event an Application does not supply the 77 | function or data, the facility still operates, and performs 78 | whatever part of its purpose remains meaningful, or 79 | 80 | b) under the GNU GPL, with none of the additional permissions of 81 | this License applicable to that copy. 82 | 83 | 3. Object Code Incorporating Material from Library Header Files. 84 | 85 | The object code form of an Application may incorporate material from 86 | a header file that is part of the Library. You may convey such object 87 | code under terms of your choice, provided that, if the incorporated 88 | material is not limited to numerical parameters, data structure 89 | layouts and accessors, or small macros, inline functions and templates 90 | (ten or fewer lines in length), you do both of the following: 91 | 92 | a) Give prominent notice with each copy of the object code that the 93 | Library is used in it and that the Library and its use are 94 | covered by this License. 95 | 96 | b) Accompany the object code with a copy of the GNU GPL and this license 97 | document. 98 | 99 | 4. Combined Works. 100 | 101 | You may convey a Combined Work under terms of your choice that, 102 | taken together, effectively do not restrict modification of the 103 | portions of the Library contained in the Combined Work and reverse 104 | engineering for debugging such modifications, if you also do each of 105 | the following: 106 | 107 | a) Give prominent notice with each copy of the Combined Work that 108 | the Library is used in it and that the Library and its use are 109 | covered by this License. 110 | 111 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 112 | document. 113 | 114 | c) For a Combined Work that displays copyright notices during 115 | execution, include the copyright notice for the Library among 116 | these notices, as well as a reference directing the user to the 117 | copies of the GNU GPL and this license document. 118 | 119 | d) Do one of the following: 120 | 121 | 0) Convey the Minimal Corresponding Source under the terms of this 122 | License, and the Corresponding Application Code in a form 123 | suitable for, and under terms that permit, the user to 124 | recombine or relink the Application with a modified version of 125 | the Linked Version to produce a modified Combined Work, in the 126 | manner specified by section 6 of the GNU GPL for conveying 127 | Corresponding Source. 128 | 129 | 1) Use a suitable shared library mechanism for linking with the 130 | Library. A suitable mechanism is one that (a) uses at run time 131 | a copy of the Library already present on the user's computer 132 | system, and (b) will operate properly with a modified version 133 | of the Library that is interface-compatible with the Linked 134 | Version. 135 | 136 | e) Provide Installation Information, but only if you would otherwise 137 | be required to provide such information under section 6 of the 138 | GNU GPL, and only to the extent that such information is 139 | necessary to install and execute a modified version of the 140 | Combined Work produced by recombining or relinking the 141 | Application with a modified version of the Linked Version. (If 142 | you use option 4d0, the Installation Information must accompany 143 | the Minimal Corresponding Source and Corresponding Application 144 | Code. If you use option 4d1, you must provide the Installation 145 | Information in the manner specified by section 6 of the GNU GPL 146 | for conveying Corresponding Source.) 147 | 148 | 5. Combined Libraries. 149 | 150 | You may place library facilities that are a work based on the 151 | Library side by side in a single library together with other library 152 | facilities that are not Applications and are not covered by this 153 | License, and convey such a combined library under terms of your 154 | choice, if you do both of the following: 155 | 156 | a) Accompany the combined library with a copy of the same work based 157 | on the Library, uncombined with any other library facilities, 158 | conveyed under the terms of this License. 159 | 160 | b) Give prominent notice with the combined library that part of it 161 | is a work based on the Library, and explaining where to find the 162 | accompanying uncombined form of the same work. 163 | 164 | 6. Revised Versions of the GNU Lesser General Public License. 165 | 166 | The Free Software Foundation may publish revised and/or new versions 167 | of the GNU Lesser General Public License from time to time. Such new 168 | versions will be similar in spirit to the present version, but may 169 | differ in detail to address new problems or concerns. 170 | 171 | Each version is given a distinguishing version number. If the 172 | Library as you received it specifies that a certain numbered version 173 | of the GNU Lesser General Public License "or any later version" 174 | applies to it, you have the option of following the terms and 175 | conditions either of that published version or of any later version 176 | published by the Free Software Foundation. If the Library as you 177 | received it does not specify a version number of the GNU Lesser 178 | General Public License, you may choose any version of the GNU Lesser 179 | General Public License ever published by the Free Software Foundation. 180 | 181 | If the Library as you received it specifies that a proxy can decide 182 | whether future versions of the GNU Lesser General Public License shall 183 | apply, that proxy's public statement of acceptance of any version is 184 | permanent authorization for you to choose that version for the 185 | Library. 186 | 187 | ==================================================================================================== 188 | ==================================================================================================== 189 | ==================================================================================================== 190 | 191 | Mozilla Public License Version 2.0 192 | ================================== 193 | 194 | 1. Definitions 195 | -------------- 196 | 197 | 1.1. "Contributor" 198 | means each individual or legal entity that creates, contributes to 199 | the creation of, or owns Covered Software. 200 | 201 | 1.2. "Contributor Version" 202 | means the combination of the Contributions of others (if any) used 203 | by a Contributor and that particular Contributor's Contribution. 204 | 205 | 1.3. "Contribution" 206 | means Covered Software of a particular Contributor. 207 | 208 | 1.4. "Covered Software" 209 | means Source Code Form to which the initial Contributor has attached 210 | the notice in Exhibit A, the Executable Form of such Source Code 211 | Form, and Modifications of such Source Code Form, in each case 212 | including portions thereof. 213 | 214 | 1.5. "Incompatible With Secondary Licenses" 215 | means 216 | 217 | (a) that the initial Contributor has attached the notice described 218 | in Exhibit B to the Covered Software; or 219 | 220 | (b) that the Covered Software was made available under the terms of 221 | version 1.1 or earlier of the License, but not also under the 222 | terms of a Secondary License. 223 | 224 | 1.6. "Executable Form" 225 | means any form of the work other than Source Code Form. 226 | 227 | 1.7. "Larger Work" 228 | means a work that combines Covered Software with other material, in 229 | a separate file or files, that is not Covered Software. 230 | 231 | 1.8. "License" 232 | means this document. 233 | 234 | 1.9. "Licensable" 235 | means having the right to grant, to the maximum extent possible, 236 | whether at the time of the initial grant or subsequently, any and 237 | all of the rights conveyed by this License. 238 | 239 | 1.10. "Modifications" 240 | means any of the following: 241 | 242 | (a) any file in Source Code Form that results from an addition to, 243 | deletion from, or modification of the contents of Covered 244 | Software; or 245 | 246 | (b) any new file in Source Code Form that contains any Covered 247 | Software. 248 | 249 | 1.11. "Patent Claims" of a Contributor 250 | means any patent claim(s), including without limitation, method, 251 | process, and apparatus claims, in any patent Licensable by such 252 | Contributor that would be infringed, but for the grant of the 253 | License, by the making, using, selling, offering for sale, having 254 | made, import, or transfer of either its Contributions or its 255 | Contributor Version. 256 | 257 | 1.12. "Secondary License" 258 | means either the GNU General Public License, Version 2.0, the GNU 259 | Lesser General Public License, Version 2.1, the GNU Affero General 260 | Public License, Version 3.0, or any later versions of those 261 | licenses. 262 | 263 | 1.13. "Source Code Form" 264 | means the form of the work preferred for making modifications. 265 | 266 | 1.14. "You" (or "Your") 267 | means an individual or a legal entity exercising rights under this 268 | License. For legal entities, "You" includes any entity that 269 | controls, is controlled by, or is under common control with You. For 270 | purposes of this definition, "control" means (a) the power, direct 271 | or indirect, to cause the direction or management of such entity, 272 | whether by contract or otherwise, or (b) ownership of more than 273 | fifty percent (50%) of the outstanding shares or beneficial 274 | ownership of such entity. 275 | 276 | 2. License Grants and Conditions 277 | -------------------------------- 278 | 279 | 2.1. Grants 280 | 281 | Each Contributor hereby grants You a world-wide, royalty-free, 282 | non-exclusive license: 283 | 284 | (a) under intellectual property rights (other than patent or trademark) 285 | Licensable by such Contributor to use, reproduce, make available, 286 | modify, display, perform, distribute, and otherwise exploit its 287 | Contributions, either on an unmodified basis, with Modifications, or 288 | as part of a Larger Work; and 289 | 290 | (b) under Patent Claims of such Contributor to make, use, sell, offer 291 | for sale, have made, import, and otherwise transfer either its 292 | Contributions or its Contributor Version. 293 | 294 | 2.2. Effective Date 295 | 296 | The licenses granted in Section 2.1 with respect to any Contribution 297 | become effective for each Contribution on the date the Contributor first 298 | distributes such Contribution. 299 | 300 | 2.3. Limitations on Grant Scope 301 | 302 | The licenses granted in this Section 2 are the only rights granted under 303 | this License. No additional rights or licenses will be implied from the 304 | distribution or licensing of Covered Software under this License. 305 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 306 | Contributor: 307 | 308 | (a) for any code that a Contributor has removed from Covered Software; 309 | or 310 | 311 | (b) for infringements caused by: (i) Your and any other third party's 312 | modifications of Covered Software, or (ii) the combination of its 313 | Contributions with other software (except as part of its Contributor 314 | Version); or 315 | 316 | (c) under Patent Claims infringed by Covered Software in the absence of 317 | its Contributions. 318 | 319 | This License does not grant any rights in the trademarks, service marks, 320 | or logos of any Contributor (except as may be necessary to comply with 321 | the notice requirements in Section 3.4). 322 | 323 | 2.4. Subsequent Licenses 324 | 325 | No Contributor makes additional grants as a result of Your choice to 326 | distribute the Covered Software under a subsequent version of this 327 | License (see Section 10.2) or under the terms of a Secondary License (if 328 | permitted under the terms of Section 3.3). 329 | 330 | 2.5. Representation 331 | 332 | Each Contributor represents that the Contributor believes its 333 | Contributions are its original creation(s) or it has sufficient rights 334 | to grant the rights to its Contributions conveyed by this License. 335 | 336 | 2.6. Fair Use 337 | 338 | This License is not intended to limit any rights You have under 339 | applicable copyright doctrines of fair use, fair dealing, or other 340 | equivalents. 341 | 342 | 2.7. Conditions 343 | 344 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 345 | in Section 2.1. 346 | 347 | 3. Responsibilities 348 | ------------------- 349 | 350 | 3.1. Distribution of Source Form 351 | 352 | All distribution of Covered Software in Source Code Form, including any 353 | Modifications that You create or to which You contribute, must be under 354 | the terms of this License. You must inform recipients that the Source 355 | Code Form of the Covered Software is governed by the terms of this 356 | License, and how they can obtain a copy of this License. You may not 357 | attempt to alter or restrict the recipients' rights in the Source Code 358 | Form. 359 | 360 | 3.2. Distribution of Executable Form 361 | 362 | If You distribute Covered Software in Executable Form then: 363 | 364 | (a) such Covered Software must also be made available in Source Code 365 | Form, as described in Section 3.1, and You must inform recipients of 366 | the Executable Form how they can obtain a copy of such Source Code 367 | Form by reasonable means in a timely manner, at a charge no more 368 | than the cost of distribution to the recipient; and 369 | 370 | (b) You may distribute such Executable Form under the terms of this 371 | License, or sublicense it under different terms, provided that the 372 | license for the Executable Form does not attempt to limit or alter 373 | the recipients' rights in the Source Code Form under this License. 374 | 375 | 3.3. Distribution of a Larger Work 376 | 377 | You may create and distribute a Larger Work under terms of Your choice, 378 | provided that You also comply with the requirements of this License for 379 | the Covered Software. If the Larger Work is a combination of Covered 380 | Software with a work governed by one or more Secondary Licenses, and the 381 | Covered Software is not Incompatible With Secondary Licenses, this 382 | License permits You to additionally distribute such Covered Software 383 | under the terms of such Secondary License(s), so that the recipient of 384 | the Larger Work may, at their option, further distribute the Covered 385 | Software under the terms of either this License or such Secondary 386 | License(s). 387 | 388 | 3.4. Notices 389 | 390 | You may not remove or alter the substance of any license notices 391 | (including copyright notices, patent notices, disclaimers of warranty, 392 | or limitations of liability) contained within the Source Code Form of 393 | the Covered Software, except that You may alter any license notices to 394 | the extent required to remedy known factual inaccuracies. 395 | 396 | 3.5. Application of Additional Terms 397 | 398 | You may choose to offer, and to charge a fee for, warranty, support, 399 | indemnity or liability obligations to one or more recipients of Covered 400 | Software. However, You may do so only on Your own behalf, and not on 401 | behalf of any Contributor. You must make it absolutely clear that any 402 | such warranty, support, indemnity, or liability obligation is offered by 403 | You alone, and You hereby agree to indemnify every Contributor for any 404 | liability incurred by such Contributor as a result of warranty, support, 405 | indemnity or liability terms You offer. You may include additional 406 | disclaimers of warranty and limitations of liability specific to any 407 | jurisdiction. 408 | 409 | 4. Inability to Comply Due to Statute or Regulation 410 | --------------------------------------------------- 411 | 412 | If it is impossible for You to comply with any of the terms of this 413 | License with respect to some or all of the Covered Software due to 414 | statute, judicial order, or regulation then You must: (a) comply with 415 | the terms of this License to the maximum extent possible; and (b) 416 | describe the limitations and the code they affect. Such description must 417 | be placed in a text file included with all distributions of the Covered 418 | Software under this License. Except to the extent prohibited by statute 419 | or regulation, such description must be sufficiently detailed for a 420 | recipient of ordinary skill to be able to understand it. 421 | 422 | 5. Termination 423 | -------------- 424 | 425 | 5.1. The rights granted under this License will terminate automatically 426 | if You fail to comply with any of its terms. However, if You become 427 | compliant, then the rights granted under this License from a particular 428 | Contributor are reinstated (a) provisionally, unless and until such 429 | Contributor explicitly and finally terminates Your grants, and (b) on an 430 | ongoing basis, if such Contributor fails to notify You of the 431 | non-compliance by some reasonable means prior to 60 days after You have 432 | come back into compliance. Moreover, Your grants from a particular 433 | Contributor are reinstated on an ongoing basis if such Contributor 434 | notifies You of the non-compliance by some reasonable means, this is the 435 | first time You have received notice of non-compliance with this License 436 | from such Contributor, and You become compliant prior to 30 days after 437 | Your receipt of the notice. 438 | 439 | 5.2. If You initiate litigation against any entity by asserting a patent 440 | infringement claim (excluding declaratory judgment actions, 441 | counter-claims, and cross-claims) alleging that a Contributor Version 442 | directly or indirectly infringes any patent, then the rights granted to 443 | You by any and all Contributors for the Covered Software under Section 444 | 2.1 of this License shall terminate. 445 | 446 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 447 | end user license agreements (excluding distributors and resellers) which 448 | have been validly granted by You or Your distributors under this License 449 | prior to termination shall survive termination. 450 | 451 | ************************************************************************ 452 | * * 453 | * 6. Disclaimer of Warranty * 454 | * ------------------------- * 455 | * * 456 | * Covered Software is provided under this License on an "as is" * 457 | * basis, without warranty of any kind, either expressed, implied, or * 458 | * statutory, including, without limitation, warranties that the * 459 | * Covered Software is free of defects, merchantable, fit for a * 460 | * particular purpose or non-infringing. The entire risk as to the * 461 | * quality and performance of the Covered Software is with You. * 462 | * Should any Covered Software prove defective in any respect, You * 463 | * (not any Contributor) assume the cost of any necessary servicing, * 464 | * repair, or correction. This disclaimer of warranty constitutes an * 465 | * essential part of this License. No use of any Covered Software is * 466 | * authorized under this License except under this disclaimer. * 467 | * * 468 | ************************************************************************ 469 | 470 | ************************************************************************ 471 | * * 472 | * 7. Limitation of Liability * 473 | * -------------------------- * 474 | * * 475 | * Under no circumstances and under no legal theory, whether tort * 476 | * (including negligence), contract, or otherwise, shall any * 477 | * Contributor, or anyone who distributes Covered Software as * 478 | * permitted above, be liable to You for any direct, indirect, * 479 | * special, incidental, or consequential damages of any character * 480 | * including, without limitation, damages for lost profits, loss of * 481 | * goodwill, work stoppage, computer failure or malfunction, or any * 482 | * and all other commercial damages or losses, even if such party * 483 | * shall have been informed of the possibility of such damages. This * 484 | * limitation of liability shall not apply to liability for death or * 485 | * personal injury resulting from such party's negligence to the * 486 | * extent applicable law prohibits such limitation. Some * 487 | * jurisdictions do not allow the exclusion or limitation of * 488 | * incidental or consequential damages, so this exclusion and * 489 | * limitation may not apply to You. * 490 | * * 491 | ************************************************************************ 492 | 493 | 8. Litigation 494 | ------------- 495 | 496 | Any litigation relating to this License may be brought only in the 497 | courts of a jurisdiction where the defendant maintains its principal 498 | place of business and such litigation shall be governed by laws of that 499 | jurisdiction, without reference to its conflict-of-law provisions. 500 | Nothing in this Section shall prevent a party's ability to bring 501 | cross-claims or counter-claims. 502 | 503 | 9. Miscellaneous 504 | ---------------- 505 | 506 | This License represents the complete agreement concerning the subject 507 | matter hereof. If any provision of this License is held to be 508 | unenforceable, such provision shall be reformed only to the extent 509 | necessary to make it enforceable. Any law or regulation which provides 510 | that the language of a contract shall be construed against the drafter 511 | shall not be used to construe this License against a Contributor. 512 | 513 | 10. Versions of the License 514 | --------------------------- 515 | 516 | 10.1. New Versions 517 | 518 | Mozilla Foundation is the license steward. Except as provided in Section 519 | 10.3, no one other than the license steward has the right to modify or 520 | publish new versions of this License. Each version will be given a 521 | distinguishing version number. 522 | 523 | 10.2. Effect of New Versions 524 | 525 | You may distribute the Covered Software under the terms of the version 526 | of the License under which You originally received the Covered Software, 527 | or under the terms of any subsequent version published by the license 528 | steward. 529 | 530 | 10.3. Modified Versions 531 | 532 | If you create software not governed by this License, and you want to 533 | create a new license for such software, you may create and use a 534 | modified version of this License if you rename the license and remove 535 | any references to the name of the license steward (except to note that 536 | such modified license differs from this License). 537 | 538 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 539 | Licenses 540 | 541 | If You choose to distribute Source Code Form that is Incompatible With 542 | Secondary Licenses under the terms of this version of the License, the 543 | notice described in Exhibit B of this License must be attached. 544 | 545 | Exhibit A - Source Code Form License Notice 546 | ------------------------------------------- 547 | 548 | This Source Code Form is subject to the terms of the Mozilla Public 549 | License, v. 2.0. If a copy of the MPL was not distributed with this 550 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 551 | 552 | If it is not possible or desirable to put the notice in a particular 553 | file, then You may include the notice in a location (such as a LICENSE 554 | file in a relevant directory) where a recipient would be likely to look 555 | for such a notice. 556 | 557 | You may add additional accurate notices of copyright ownership. 558 | 559 | Exhibit B - "Incompatible With Secondary Licenses" Notice 560 | --------------------------------------------------------- 561 | 562 | This Source Code Form is "Incompatible With Secondary Licenses", as 563 | defined by the Mozilla Public License, v. 2.0. 564 | 565 | ==================================================================================================== 566 | ==================================================================================================== 567 | ==================================================================================================== -------------------------------------------------------------------------------- /lib/symmetric/aes/engine.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:ninja/block_cipher/block_cipher.dart'; 4 | import 'package:ninja/utils/ufixnum.dart'; 5 | 6 | // [AESFastEncryptionEngine] and [AESFastDecryptionEngine] are copied and 7 | // modified from pointy_castles package. See file LICENSE/pointy_castle_LICENSE 8 | // file for more information. 9 | 10 | /// An implementation of the AES (Rijndael), from FIPS-197. 11 | /// 12 | /// This implementation is based on optimizations from Dr. Brian Gladman's paper 13 | /// and C code at [http://fp.gladman.plus.com/cryptography_technology/rijndael/] 14 | /// 15 | /// There are three levels of tradeoff of speed vs memory and they are written 16 | /// as three separate classes from which to choose. 17 | /// 18 | /// The fastest uses 8Kbytes of static tables to precompute round calculations, 19 | /// 4 256 word tables for encryption and 4 for decryption. 20 | /// 21 | /// The middle performance version uses only one 256 word table for each, for a 22 | /// total of 2Kbytes, adding 12 rotate operations per round to compute the values 23 | /// contained in the other tables from the contents of the first. 24 | /// 25 | /// The slowest version uses no static tables at all and computes the values in 26 | /// each round. 27 | /// This file contains the fast version with 8Kbytes of static tables for round 28 | /// precomputation. 29 | abstract class _Common { 30 | int get _c0; 31 | 32 | set _c0(int value); 33 | 34 | int get _c1; 35 | 36 | set _c1(int value); 37 | 38 | int get _c2; 39 | 40 | set _c2(int value); 41 | 42 | int get _c3; 43 | 44 | set _c3(int value); 45 | 46 | void _unpackBlock(ByteData view) { 47 | _c0 = view.getUint32(0, Endian.little); 48 | _c1 = view.getUint32(4, Endian.little); 49 | _c2 = view.getUint32(8, Endian.little); 50 | _c3 = view.getUint32(12, Endian.little); 51 | } 52 | 53 | void _packBlock(ByteData view) { 54 | view.setUint32(0, _c0, Endian.little); 55 | view.setUint32(4, _c1, Endian.little); 56 | view.setUint32(8, _c2, Endian.little); 57 | view.setUint32(12, _c3, Endian.little); 58 | } 59 | 60 | void reset() { 61 | _c0 = 0; 62 | _c1 = 0; 63 | _c2 = 0; 64 | _c3 = 0; 65 | } 66 | 67 | int get blockSize; 68 | 69 | int processBlock(ByteData input, ByteData output); 70 | 71 | Uint8List process(Uint8List data) { 72 | final numBlocks = (data.length / blockSize).ceil(); 73 | final out = Uint8List(numBlocks * blockSize); 74 | 75 | int offset = 0; 76 | for (int i = 0; i < numBlocks; i++) { 77 | final inputBlock = data.buffer.asByteData(offset, blockSize); 78 | final outputBlock = out.buffer.asByteData(offset, blockSize); 79 | processBlock(inputBlock, outputBlock); 80 | offset += blockSize; 81 | } 82 | 83 | return out; 84 | } 85 | } 86 | 87 | class AESFastEncryptionEngine extends _Common implements BlockCipher { 88 | static const _block_size = 16; 89 | 90 | List> _workingKey; 91 | int _rounds = 0; 92 | int _c0 = 0, _c1 = 0, _c2 = 0, _c3 = 0; 93 | 94 | final int blockSize = _block_size; 95 | 96 | AESFastEncryptionEngine._(this._workingKey, this._rounds); 97 | 98 | factory AESFastEncryptionEngine(Uint8List key) { 99 | int KC = (key.lengthInBytes / 4).floor(); // key length in words 100 | if (((KC != 4) && (KC != 6) && (KC != 8)) || 101 | ((KC * 4) != key.lengthInBytes)) { 102 | throw ArgumentError("Key length must be 128/192/256 bits"); 103 | } 104 | 105 | final int _rounds = KC + 106 | 6; // This is not always true for the generalized Rijndael that allows larger block sizes 107 | final List> _workingKey = List.generate( 108 | _rounds + 1, (int i) => List.filled(4, 0)); // 4 words in a block 109 | 110 | // Copy the key into the round key array. 111 | var keyView = ByteData.view(key.buffer, key.offsetInBytes, key.length); 112 | for (int i = 0, t = 0; i < key.lengthInBytes; i += 4, t++) { 113 | int value = keyView.getUint32(i, Endian.little); 114 | _workingKey[t >> 2][t & 3] = value; 115 | } 116 | 117 | // While not enough round key material calculated calculate new values. 118 | int k = (_rounds + 1) << 2; 119 | for (int i = KC; i < k; i++) { 120 | int temp = _workingKey[(i - 1) >> 2][(i - 1) & 3].toInt(); 121 | if ((i % KC) == 0) { 122 | temp = _subWord(_shift(temp, 8)) ^ _rcon[((i / KC) - 1).floor()]; 123 | } else if ((KC > 6) && ((i % KC) == 4)) { 124 | temp = _subWord(temp); 125 | } 126 | 127 | int value = _workingKey[(i - KC) >> 2][(i - KC) & 3] ^ temp; 128 | _workingKey[i >> 2][i & 3] = value; 129 | } 130 | 131 | return AESFastEncryptionEngine._(_workingKey, _rounds); 132 | } 133 | 134 | int processBlock(ByteData input, ByteData output) { 135 | if (input.lengthInBytes < blockSize) { 136 | throw ArgumentError("Input buffer too short"); 137 | } 138 | 139 | if (output.lengthInBytes < blockSize) { 140 | throw ArgumentError("Output buffer too short"); 141 | } 142 | 143 | _unpackBlock(input); 144 | _encryptBlock(_workingKey); 145 | _packBlock(output); 146 | 147 | return blockSize; 148 | } 149 | 150 | void _encryptBlock(List> KW) { 151 | int r, r0, r1, r2, r3; 152 | 153 | _c0 ^= KW[0][0].toInt(); 154 | _c1 ^= KW[0][1].toInt(); 155 | _c2 ^= KW[0][2].toInt(); 156 | _c3 ^= KW[0][3].toInt(); 157 | 158 | r = 1; 159 | while (r < _rounds - 1) { 160 | r0 = _T0[_c0 & 255] ^ 161 | _T1[(_c1 >> 8) & 255] ^ 162 | _T2[(_c2 >> 16) & 255] ^ 163 | _T3[(_c3 >> 24) & 255] ^ 164 | KW[r][0].toInt(); 165 | r1 = _T0[_c1 & 255] ^ 166 | _T1[(_c2 >> 8) & 255] ^ 167 | _T2[(_c3 >> 16) & 255] ^ 168 | _T3[(_c0 >> 24) & 255] ^ 169 | KW[r][1].toInt(); 170 | r2 = _T0[_c2 & 255] ^ 171 | _T1[(_c3 >> 8) & 255] ^ 172 | _T2[(_c0 >> 16) & 255] ^ 173 | _T3[(_c1 >> 24) & 255] ^ 174 | KW[r][2].toInt(); 175 | r3 = _T0[_c3 & 255] ^ 176 | _T1[(_c0 >> 8) & 255] ^ 177 | _T2[(_c1 >> 16) & 255] ^ 178 | _T3[(_c2 >> 24) & 255] ^ 179 | KW[r][3].toInt(); 180 | r++; 181 | _c0 = _T0[r0 & 255] ^ 182 | _T1[(r1 >> 8) & 255] ^ 183 | _T2[(r2 >> 16) & 255] ^ 184 | _T3[(r3 >> 24) & 255] ^ 185 | KW[r][0].toInt(); 186 | _c1 = _T0[r1 & 255] ^ 187 | _T1[(r2 >> 8) & 255] ^ 188 | _T2[(r3 >> 16) & 255] ^ 189 | _T3[(r0 >> 24) & 255] ^ 190 | KW[r][1].toInt(); 191 | _c2 = _T0[r2 & 255] ^ 192 | _T1[(r3 >> 8) & 255] ^ 193 | _T2[(r0 >> 16) & 255] ^ 194 | _T3[(r1 >> 24) & 255] ^ 195 | KW[r][2].toInt(); 196 | _c3 = _T0[r3 & 255] ^ 197 | _T1[(r0 >> 8) & 255] ^ 198 | _T2[(r1 >> 16) & 255] ^ 199 | _T3[(r2 >> 24) & 255] ^ 200 | KW[r][3].toInt(); 201 | r++; 202 | } 203 | 204 | r0 = _T0[_c0 & 255] ^ 205 | _T1[(_c1 >> 8) & 255] ^ 206 | _T2[(_c2 >> 16) & 255] ^ 207 | _T3[(_c3 >> 24) & 255] ^ 208 | KW[r][0].toInt(); 209 | r1 = _T0[_c1 & 255] ^ 210 | _T1[(_c2 >> 8) & 255] ^ 211 | _T2[(_c3 >> 16) & 255] ^ 212 | _T3[(_c0 >> 24) & 255] ^ 213 | KW[r][1].toInt(); 214 | r2 = _T0[_c2 & 255] ^ 215 | _T1[(_c3 >> 8) & 255] ^ 216 | _T2[(_c0 >> 16) & 255] ^ 217 | _T3[(_c1 >> 24) & 255] ^ 218 | KW[r][2].toInt(); 219 | r3 = _T0[_c3 & 255] ^ 220 | _T1[(_c0 >> 8) & 255] ^ 221 | _T2[(_c1 >> 16) & 255] ^ 222 | _T3[(_c2 >> 24) & 255] ^ 223 | KW[r][3].toInt(); 224 | r++; 225 | 226 | // the final round's table is a simple function of S so we don't use a whole other four tables for it 227 | _c0 = (_S[r0 & 255] & 255) ^ 228 | ((_S[(r1 >> 8) & 255] & 255) << 8) ^ 229 | ((_S[(r2 >> 16) & 255] & 255) << 16) ^ 230 | (_S[(r3 >> 24) & 255] << 24) ^ 231 | KW[r][0].toInt(); 232 | _c1 = (_S[r1 & 255] & 255) ^ 233 | ((_S[(r2 >> 8) & 255] & 255) << 8) ^ 234 | ((_S[(r3 >> 16) & 255] & 255) << 16) ^ 235 | (_S[(r0 >> 24) & 255] << 24) ^ 236 | KW[r][1].toInt(); 237 | _c2 = (_S[r2 & 255] & 255) ^ 238 | ((_S[(r3 >> 8) & 255] & 255) << 8) ^ 239 | ((_S[(r0 >> 16) & 255] & 255) << 16) ^ 240 | (_S[(r1 >> 24) & 255] << 24) ^ 241 | KW[r][2].toInt(); 242 | _c3 = (_S[r3 & 255] & 255) ^ 243 | ((_S[(r0 >> 8) & 255] & 255) << 8) ^ 244 | ((_S[(r1 >> 16) & 255] & 255) << 16) ^ 245 | (_S[(r2 >> 24) & 255] << 24) ^ 246 | KW[r][3].toInt(); 247 | } 248 | } 249 | 250 | class AESFastDecryptionEngine extends _Common implements BlockCipher { 251 | static const _blockSize = 16; 252 | 253 | final List> _workingKey; 254 | final int _rounds; 255 | int _c0 = 0, _c1 = 0, _c2 = 0, _c3 = 0; 256 | 257 | final int blockSize = _blockSize; 258 | 259 | AESFastDecryptionEngine._(this._workingKey, this._rounds); 260 | 261 | factory AESFastDecryptionEngine(Uint8List key) { 262 | int KC = (key.lengthInBytes / 4).floor(); // key length in words 263 | if (((KC != 4) && (KC != 6) && (KC != 8)) || 264 | ((KC * 4) != key.lengthInBytes)) { 265 | throw ArgumentError("Key length must be 128/192/256 bits"); 266 | } 267 | 268 | final int _rounds = KC + 6; 269 | // This is not always true for the generalized Rijndael that allows larger block sizes 270 | final List> _workingKey = List.generate( 271 | _rounds + 1, (int i) => List.filled(4, 0)); // 4 words in a block 272 | 273 | // Copy the key into the round key array. 274 | var keyView = ByteData.view(key.buffer, key.offsetInBytes, key.length); 275 | for (int i = 0, t = 0; i < key.lengthInBytes; i += 4, t++) { 276 | int value = keyView.getUint32(i, Endian.little); 277 | _workingKey[t >> 2][t & 3] = value; 278 | } 279 | 280 | // While not enough round key material calculated calculate new values. 281 | int k = (_rounds + 1) << 2; 282 | for (int i = KC; i < k; i++) { 283 | int temp = _workingKey[(i - 1) >> 2][(i - 1) & 3].toInt(); 284 | if ((i % KC) == 0) { 285 | temp = _subWord(_shift(temp, 8)) ^ _rcon[((i / KC) - 1).floor()]; 286 | } else if ((KC > 6) && ((i % KC) == 4)) { 287 | temp = _subWord(temp); 288 | } 289 | 290 | int value = _workingKey[(i - KC) >> 2][(i - KC) & 3] ^ temp; 291 | _workingKey[i >> 2][i & 3] = value; 292 | } 293 | 294 | for (int j = 1; j < _rounds; j++) { 295 | for (int i = 0; i < 4; i++) { 296 | var value = _inv_mcol(_workingKey[j][i].toInt()); 297 | _workingKey[j][i] = value; 298 | } 299 | } 300 | 301 | return AESFastDecryptionEngine._(_workingKey, _rounds); 302 | } 303 | 304 | int processBlock(ByteData input, ByteData output) { 305 | if (input.lengthInBytes < blockSize) { 306 | throw ArgumentError("Input buffer too short"); 307 | } 308 | 309 | if (output.lengthInBytes < blockSize) { 310 | throw ArgumentError("Output buffer too short"); 311 | } 312 | 313 | _unpackBlock(input); 314 | _decryptBlock(_workingKey); 315 | _packBlock(output); 316 | 317 | return _blockSize; 318 | } 319 | 320 | void _decryptBlock(List> KW) { 321 | int r, r0, r1, r2, r3; 322 | 323 | _c0 ^= KW[_rounds][0].toInt(); 324 | _c1 ^= KW[_rounds][1].toInt(); 325 | _c2 ^= KW[_rounds][2].toInt(); 326 | _c3 ^= KW[_rounds][3].toInt(); 327 | 328 | r = _rounds - 1; 329 | while (r > 1) { 330 | r0 = _Tinv0[_c0 & 255] ^ 331 | _Tinv1[(_c3 >> 8) & 255] ^ 332 | _Tinv2[(_c2 >> 16) & 255] ^ 333 | _Tinv3[(_c1 >> 24) & 255] ^ 334 | KW[r][0].toInt(); 335 | r1 = _Tinv0[_c1 & 255] ^ 336 | _Tinv1[(_c0 >> 8) & 255] ^ 337 | _Tinv2[(_c3 >> 16) & 255] ^ 338 | _Tinv3[(_c2 >> 24) & 255] ^ 339 | KW[r][1].toInt(); 340 | r2 = _Tinv0[_c2 & 255] ^ 341 | _Tinv1[(_c1 >> 8) & 255] ^ 342 | _Tinv2[(_c0 >> 16) & 255] ^ 343 | _Tinv3[(_c3 >> 24) & 255] ^ 344 | KW[r][2].toInt(); 345 | r3 = _Tinv0[_c3 & 255] ^ 346 | _Tinv1[(_c2 >> 8) & 255] ^ 347 | _Tinv2[(_c1 >> 16) & 255] ^ 348 | _Tinv3[(_c0 >> 24) & 255] ^ 349 | KW[r][3].toInt(); 350 | r--; 351 | _c0 = _Tinv0[r0 & 255] ^ 352 | _Tinv1[(r3 >> 8) & 255] ^ 353 | _Tinv2[(r2 >> 16) & 255] ^ 354 | _Tinv3[(r1 >> 24) & 255] ^ 355 | KW[r][0].toInt(); 356 | _c1 = _Tinv0[r1 & 255] ^ 357 | _Tinv1[(r0 >> 8) & 255] ^ 358 | _Tinv2[(r3 >> 16) & 255] ^ 359 | _Tinv3[(r2 >> 24) & 255] ^ 360 | KW[r][1].toInt(); 361 | _c2 = _Tinv0[r2 & 255] ^ 362 | _Tinv1[(r1 >> 8) & 255] ^ 363 | _Tinv2[(r0 >> 16) & 255] ^ 364 | _Tinv3[(r3 >> 24) & 255] ^ 365 | KW[r][2].toInt(); 366 | _c3 = _Tinv0[r3 & 255] ^ 367 | _Tinv1[(r2 >> 8) & 255] ^ 368 | _Tinv2[(r1 >> 16) & 255] ^ 369 | _Tinv3[(r0 >> 24) & 255] ^ 370 | KW[r][3].toInt(); 371 | r--; 372 | } 373 | 374 | r0 = _Tinv0[_c0 & 255] ^ 375 | _Tinv1[(_c3 >> 8) & 255] ^ 376 | _Tinv2[(_c2 >> 16) & 255] ^ 377 | _Tinv3[(_c1 >> 24) & 255] ^ 378 | KW[r][0].toInt(); 379 | r1 = _Tinv0[_c1 & 255] ^ 380 | _Tinv1[(_c0 >> 8) & 255] ^ 381 | _Tinv2[(_c3 >> 16) & 255] ^ 382 | _Tinv3[(_c2 >> 24) & 255] ^ 383 | KW[r][1].toInt(); 384 | r2 = _Tinv0[_c2 & 255] ^ 385 | _Tinv1[(_c1 >> 8) & 255] ^ 386 | _Tinv2[(_c0 >> 16) & 255] ^ 387 | _Tinv3[(_c3 >> 24) & 255] ^ 388 | KW[r][2].toInt(); 389 | r3 = _Tinv0[_c3 & 255] ^ 390 | _Tinv1[(_c2 >> 8) & 255] ^ 391 | _Tinv2[(_c1 >> 16) & 255] ^ 392 | _Tinv3[(_c0 >> 24) & 255] ^ 393 | KW[r][3].toInt(); 394 | 395 | // the final round's table is a simple function of Si so we don't use a whole other four tables for it 396 | _c0 = (_Si[r0 & 255] & 255) ^ 397 | ((_Si[(r3 >> 8) & 255] & 255) << 8) ^ 398 | ((_Si[(r2 >> 16) & 255] & 255) << 16) ^ 399 | (_Si[(r1 >> 24) & 255] << 24) ^ 400 | KW[0][0].toInt(); 401 | _c1 = (_Si[r1 & 255] & 255) ^ 402 | ((_Si[(r0 >> 8) & 255] & 255) << 8) ^ 403 | ((_Si[(r3 >> 16) & 255] & 255) << 16) ^ 404 | (_Si[(r2 >> 24) & 255] << 24) ^ 405 | KW[0][1].toInt(); 406 | _c2 = (_Si[r2 & 255] & 255) ^ 407 | ((_Si[(r1 >> 8) & 255] & 255) << 8) ^ 408 | ((_Si[(r0 >> 16) & 255] & 255) << 16) ^ 409 | (_Si[(r3 >> 24) & 255] << 24) ^ 410 | KW[0][2].toInt(); 411 | _c3 = (_Si[r3 & 255] & 255) ^ 412 | ((_Si[(r2 >> 8) & 255] & 255) << 8) ^ 413 | ((_Si[(r1 >> 16) & 255] & 255) << 16) ^ 414 | (_Si[(r0 >> 24) & 255] << 24) ^ 415 | KW[0][3].toInt(); 416 | } 417 | } 418 | 419 | int _shift(int r, int shift) => rotr32(r, shift); 420 | 421 | /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ 422 | 423 | const int _m1 = 0x80808080; 424 | const int _m2 = 0x7f7f7f7f; 425 | const int _m3 = 0x0000001b; 426 | 427 | int _FFmulX(int x) { 428 | var lsr = shiftr32((x & _m1), 7); 429 | return (((x & _m2) << 1) ^ lsr * _m3); 430 | } 431 | 432 | /* 433 | The following defines provide alternative definitions of FFmulX that might 434 | give improved performance if a fast 32-bit multiply is not available. 435 | private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 436 | private static final int m4 = 0x1b1b1b1b; 437 | private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 438 | */ 439 | 440 | int _inv_mcol(int x) { 441 | int f2 = _FFmulX(x); 442 | int f4 = _FFmulX(f2); 443 | int f8 = _FFmulX(f4); 444 | int f9 = x ^ f8; 445 | 446 | return f2 ^ 447 | f4 ^ 448 | f8 ^ 449 | _shift(f2 ^ f9, 8) ^ 450 | _shift(f4 ^ f9, 16) ^ 451 | _shift(f9, 24); 452 | } 453 | 454 | int _subWord(int x) { 455 | return (_S[x & 255] & 255 | 456 | ((_S[(x >> 8) & 255] & 255) << 8) | 457 | ((_S[(x >> 16) & 255] & 255) << 16) | 458 | _S[(x >> 24) & 255] << 24); 459 | } 460 | 461 | // The S box 462 | final _S = [ 463 | 99, 464 | 124, 465 | 119, 466 | 123, 467 | 242, 468 | 107, 469 | 111, 470 | 197, 471 | 48, 472 | 1, 473 | 103, 474 | 43, 475 | 254, 476 | 215, 477 | 171, 478 | 118, 479 | 202, 480 | 130, 481 | 201, 482 | 125, 483 | 250, 484 | 89, 485 | 71, 486 | 240, 487 | 173, 488 | 212, 489 | 162, 490 | 175, 491 | 156, 492 | 164, 493 | 114, 494 | 192, 495 | 183, 496 | 253, 497 | 147, 498 | 38, 499 | 54, 500 | 63, 501 | 247, 502 | 204, 503 | 52, 504 | 165, 505 | 229, 506 | 241, 507 | 113, 508 | 216, 509 | 49, 510 | 21, 511 | 4, 512 | 199, 513 | 35, 514 | 195, 515 | 24, 516 | 150, 517 | 5, 518 | 154, 519 | 7, 520 | 18, 521 | 128, 522 | 226, 523 | 235, 524 | 39, 525 | 178, 526 | 117, 527 | 9, 528 | 131, 529 | 44, 530 | 26, 531 | 27, 532 | 110, 533 | 90, 534 | 160, 535 | 82, 536 | 59, 537 | 214, 538 | 179, 539 | 41, 540 | 227, 541 | 47, 542 | 132, 543 | 83, 544 | 209, 545 | 0, 546 | 237, 547 | 32, 548 | 252, 549 | 177, 550 | 91, 551 | 106, 552 | 203, 553 | 190, 554 | 57, 555 | 74, 556 | 76, 557 | 88, 558 | 207, 559 | 208, 560 | 239, 561 | 170, 562 | 251, 563 | 67, 564 | 77, 565 | 51, 566 | 133, 567 | 69, 568 | 249, 569 | 2, 570 | 127, 571 | 80, 572 | 60, 573 | 159, 574 | 168, 575 | 81, 576 | 163, 577 | 64, 578 | 143, 579 | 146, 580 | 157, 581 | 56, 582 | 245, 583 | 188, 584 | 182, 585 | 218, 586 | 33, 587 | 16, 588 | 255, 589 | 243, 590 | 210, 591 | 205, 592 | 12, 593 | 19, 594 | 236, 595 | 95, 596 | 151, 597 | 68, 598 | 23, 599 | 196, 600 | 167, 601 | 126, 602 | 61, 603 | 100, 604 | 93, 605 | 25, 606 | 115, 607 | 96, 608 | 129, 609 | 79, 610 | 220, 611 | 34, 612 | 42, 613 | 144, 614 | 136, 615 | 70, 616 | 238, 617 | 184, 618 | 20, 619 | 222, 620 | 94, 621 | 11, 622 | 219, 623 | 224, 624 | 50, 625 | 58, 626 | 10, 627 | 73, 628 | 6, 629 | 36, 630 | 92, 631 | 194, 632 | 211, 633 | 172, 634 | 98, 635 | 145, 636 | 149, 637 | 228, 638 | 121, 639 | 231, 640 | 200, 641 | 55, 642 | 109, 643 | 141, 644 | 213, 645 | 78, 646 | 169, 647 | 108, 648 | 86, 649 | 244, 650 | 234, 651 | 101, 652 | 122, 653 | 174, 654 | 8, 655 | 186, 656 | 120, 657 | 37, 658 | 46, 659 | 28, 660 | 166, 661 | 180, 662 | 198, 663 | 232, 664 | 221, 665 | 116, 666 | 31, 667 | 75, 668 | 189, 669 | 139, 670 | 138, 671 | 112, 672 | 62, 673 | 181, 674 | 102, 675 | 72, 676 | 3, 677 | 246, 678 | 14, 679 | 97, 680 | 53, 681 | 87, 682 | 185, 683 | 134, 684 | 193, 685 | 29, 686 | 158, 687 | 225, 688 | 248, 689 | 152, 690 | 17, 691 | 105, 692 | 217, 693 | 142, 694 | 148, 695 | 155, 696 | 30, 697 | 135, 698 | 233, 699 | 206, 700 | 85, 701 | 40, 702 | 223, 703 | 140, 704 | 161, 705 | 137, 706 | 13, 707 | 191, 708 | 230, 709 | 66, 710 | 104, 711 | 65, 712 | 153, 713 | 45, 714 | 15, 715 | 176, 716 | 84, 717 | 187, 718 | 22 719 | ]; 720 | 721 | // The inverse S-box 722 | final _Si = [ 723 | 82, 724 | 9, 725 | 106, 726 | 213, 727 | 48, 728 | 54, 729 | 165, 730 | 56, 731 | 191, 732 | 64, 733 | 163, 734 | 158, 735 | 129, 736 | 243, 737 | 215, 738 | 251, 739 | 124, 740 | 227, 741 | 57, 742 | 130, 743 | 155, 744 | 47, 745 | 255, 746 | 135, 747 | 52, 748 | 142, 749 | 67, 750 | 68, 751 | 196, 752 | 222, 753 | 233, 754 | 203, 755 | 84, 756 | 123, 757 | 148, 758 | 50, 759 | 166, 760 | 194, 761 | 35, 762 | 61, 763 | 238, 764 | 76, 765 | 149, 766 | 11, 767 | 66, 768 | 250, 769 | 195, 770 | 78, 771 | 8, 772 | 46, 773 | 161, 774 | 102, 775 | 40, 776 | 217, 777 | 36, 778 | 178, 779 | 118, 780 | 91, 781 | 162, 782 | 73, 783 | 109, 784 | 139, 785 | 209, 786 | 37, 787 | 114, 788 | 248, 789 | 246, 790 | 100, 791 | 134, 792 | 104, 793 | 152, 794 | 22, 795 | 212, 796 | 164, 797 | 92, 798 | 204, 799 | 93, 800 | 101, 801 | 182, 802 | 146, 803 | 108, 804 | 112, 805 | 72, 806 | 80, 807 | 253, 808 | 237, 809 | 185, 810 | 218, 811 | 94, 812 | 21, 813 | 70, 814 | 87, 815 | 167, 816 | 141, 817 | 157, 818 | 132, 819 | 144, 820 | 216, 821 | 171, 822 | 0, 823 | 140, 824 | 188, 825 | 211, 826 | 10, 827 | 247, 828 | 228, 829 | 88, 830 | 5, 831 | 184, 832 | 179, 833 | 69, 834 | 6, 835 | 208, 836 | 44, 837 | 30, 838 | 143, 839 | 202, 840 | 63, 841 | 15, 842 | 2, 843 | 193, 844 | 175, 845 | 189, 846 | 3, 847 | 1, 848 | 19, 849 | 138, 850 | 107, 851 | 58, 852 | 145, 853 | 17, 854 | 65, 855 | 79, 856 | 103, 857 | 220, 858 | 234, 859 | 151, 860 | 242, 861 | 207, 862 | 206, 863 | 240, 864 | 180, 865 | 230, 866 | 115, 867 | 150, 868 | 172, 869 | 116, 870 | 34, 871 | 231, 872 | 173, 873 | 53, 874 | 133, 875 | 226, 876 | 249, 877 | 55, 878 | 232, 879 | 28, 880 | 117, 881 | 223, 882 | 110, 883 | 71, 884 | 241, 885 | 26, 886 | 113, 887 | 29, 888 | 41, 889 | 197, 890 | 137, 891 | 111, 892 | 183, 893 | 98, 894 | 14, 895 | 170, 896 | 24, 897 | 190, 898 | 27, 899 | 252, 900 | 86, 901 | 62, 902 | 75, 903 | 198, 904 | 210, 905 | 121, 906 | 32, 907 | 154, 908 | 219, 909 | 192, 910 | 254, 911 | 120, 912 | 205, 913 | 90, 914 | 244, 915 | 31, 916 | 221, 917 | 168, 918 | 51, 919 | 136, 920 | 7, 921 | 199, 922 | 49, 923 | 177, 924 | 18, 925 | 16, 926 | 89, 927 | 39, 928 | 128, 929 | 236, 930 | 95, 931 | 96, 932 | 81, 933 | 127, 934 | 169, 935 | 25, 936 | 181, 937 | 74, 938 | 13, 939 | 45, 940 | 229, 941 | 122, 942 | 159, 943 | 147, 944 | 201, 945 | 156, 946 | 239, 947 | 160, 948 | 224, 949 | 59, 950 | 77, 951 | 174, 952 | 42, 953 | 245, 954 | 176, 955 | 200, 956 | 235, 957 | 187, 958 | 60, 959 | 131, 960 | 83, 961 | 153, 962 | 97, 963 | 23, 964 | 43, 965 | 4, 966 | 126, 967 | 186, 968 | 119, 969 | 214, 970 | 38, 971 | 225, 972 | 105, 973 | 20, 974 | 99, 975 | 85, 976 | 33, 977 | 12, 978 | 125, 979 | ]; 980 | 981 | // vector used in calculating key schedule (powers of x in GF(256)) 982 | final _rcon = [ 983 | 0x01, 984 | 0x02, 985 | 0x04, 986 | 0x08, 987 | 0x10, 988 | 0x20, 989 | 0x40, 990 | 0x80, 991 | 0x1b, 992 | 0x36, 993 | 0x6c, 994 | 0xd8, 995 | 0xab, 996 | 0x4d, 997 | 0x9a, 998 | 0x2f, 999 | 0x5e, 1000 | 0xbc, 1001 | 0x63, 1002 | 0xc6, 1003 | 0x97, 1004 | 0x35, 1005 | 0x6a, 1006 | 0xd4, 1007 | 0xb3, 1008 | 0x7d, 1009 | 0xfa, 1010 | 0xef, 1011 | 0xc5, 1012 | 0x91 1013 | ]; 1014 | 1015 | // precomputation tables of calculations for rounds 1016 | final _T0 = [ 1017 | 0xa56363c6, 1018 | 0x847c7cf8, 1019 | 0x997777ee, 1020 | 0x8d7b7bf6, 1021 | 0x0df2f2ff, 1022 | 0xbd6b6bd6, 1023 | 0xb16f6fde, 1024 | 0x54c5c591, 1025 | 0x50303060, 1026 | 0x03010102, 1027 | 0xa96767ce, 1028 | 0x7d2b2b56, 1029 | 0x19fefee7, 1030 | 0x62d7d7b5, 1031 | 0xe6abab4d, 1032 | 0x9a7676ec, 1033 | 0x45caca8f, 1034 | 0x9d82821f, 1035 | 0x40c9c989, 1036 | 0x877d7dfa, 1037 | 0x15fafaef, 1038 | 0xeb5959b2, 1039 | 0xc947478e, 1040 | 0x0bf0f0fb, 1041 | 0xecadad41, 1042 | 0x67d4d4b3, 1043 | 0xfda2a25f, 1044 | 0xeaafaf45, 1045 | 0xbf9c9c23, 1046 | 0xf7a4a453, 1047 | 0x967272e4, 1048 | 0x5bc0c09b, 1049 | 0xc2b7b775, 1050 | 0x1cfdfde1, 1051 | 0xae93933d, 1052 | 0x6a26264c, 1053 | 0x5a36366c, 1054 | 0x413f3f7e, 1055 | 0x02f7f7f5, 1056 | 0x4fcccc83, 1057 | 0x5c343468, 1058 | 0xf4a5a551, 1059 | 0x34e5e5d1, 1060 | 0x08f1f1f9, 1061 | 0x937171e2, 1062 | 0x73d8d8ab, 1063 | 0x53313162, 1064 | 0x3f15152a, 1065 | 0x0c040408, 1066 | 0x52c7c795, 1067 | 0x65232346, 1068 | 0x5ec3c39d, 1069 | 0x28181830, 1070 | 0xa1969637, 1071 | 0x0f05050a, 1072 | 0xb59a9a2f, 1073 | 0x0907070e, 1074 | 0x36121224, 1075 | 0x9b80801b, 1076 | 0x3de2e2df, 1077 | 0x26ebebcd, 1078 | 0x6927274e, 1079 | 0xcdb2b27f, 1080 | 0x9f7575ea, 1081 | 0x1b090912, 1082 | 0x9e83831d, 1083 | 0x742c2c58, 1084 | 0x2e1a1a34, 1085 | 0x2d1b1b36, 1086 | 0xb26e6edc, 1087 | 0xee5a5ab4, 1088 | 0xfba0a05b, 1089 | 0xf65252a4, 1090 | 0x4d3b3b76, 1091 | 0x61d6d6b7, 1092 | 0xceb3b37d, 1093 | 0x7b292952, 1094 | 0x3ee3e3dd, 1095 | 0x712f2f5e, 1096 | 0x97848413, 1097 | 0xf55353a6, 1098 | 0x68d1d1b9, 1099 | 0x00000000, 1100 | 0x2cededc1, 1101 | 0x60202040, 1102 | 0x1ffcfce3, 1103 | 0xc8b1b179, 1104 | 0xed5b5bb6, 1105 | 0xbe6a6ad4, 1106 | 0x46cbcb8d, 1107 | 0xd9bebe67, 1108 | 0x4b393972, 1109 | 0xde4a4a94, 1110 | 0xd44c4c98, 1111 | 0xe85858b0, 1112 | 0x4acfcf85, 1113 | 0x6bd0d0bb, 1114 | 0x2aefefc5, 1115 | 0xe5aaaa4f, 1116 | 0x16fbfbed, 1117 | 0xc5434386, 1118 | 0xd74d4d9a, 1119 | 0x55333366, 1120 | 0x94858511, 1121 | 0xcf45458a, 1122 | 0x10f9f9e9, 1123 | 0x06020204, 1124 | 0x817f7ffe, 1125 | 0xf05050a0, 1126 | 0x443c3c78, 1127 | 0xba9f9f25, 1128 | 0xe3a8a84b, 1129 | 0xf35151a2, 1130 | 0xfea3a35d, 1131 | 0xc0404080, 1132 | 0x8a8f8f05, 1133 | 0xad92923f, 1134 | 0xbc9d9d21, 1135 | 0x48383870, 1136 | 0x04f5f5f1, 1137 | 0xdfbcbc63, 1138 | 0xc1b6b677, 1139 | 0x75dadaaf, 1140 | 0x63212142, 1141 | 0x30101020, 1142 | 0x1affffe5, 1143 | 0x0ef3f3fd, 1144 | 0x6dd2d2bf, 1145 | 0x4ccdcd81, 1146 | 0x140c0c18, 1147 | 0x35131326, 1148 | 0x2fececc3, 1149 | 0xe15f5fbe, 1150 | 0xa2979735, 1151 | 0xcc444488, 1152 | 0x3917172e, 1153 | 0x57c4c493, 1154 | 0xf2a7a755, 1155 | 0x827e7efc, 1156 | 0x473d3d7a, 1157 | 0xac6464c8, 1158 | 0xe75d5dba, 1159 | 0x2b191932, 1160 | 0x957373e6, 1161 | 0xa06060c0, 1162 | 0x98818119, 1163 | 0xd14f4f9e, 1164 | 0x7fdcdca3, 1165 | 0x66222244, 1166 | 0x7e2a2a54, 1167 | 0xab90903b, 1168 | 0x8388880b, 1169 | 0xca46468c, 1170 | 0x29eeeec7, 1171 | 0xd3b8b86b, 1172 | 0x3c141428, 1173 | 0x79dedea7, 1174 | 0xe25e5ebc, 1175 | 0x1d0b0b16, 1176 | 0x76dbdbad, 1177 | 0x3be0e0db, 1178 | 0x56323264, 1179 | 0x4e3a3a74, 1180 | 0x1e0a0a14, 1181 | 0xdb494992, 1182 | 0x0a06060c, 1183 | 0x6c242448, 1184 | 0xe45c5cb8, 1185 | 0x5dc2c29f, 1186 | 0x6ed3d3bd, 1187 | 0xefacac43, 1188 | 0xa66262c4, 1189 | 0xa8919139, 1190 | 0xa4959531, 1191 | 0x37e4e4d3, 1192 | 0x8b7979f2, 1193 | 0x32e7e7d5, 1194 | 0x43c8c88b, 1195 | 0x5937376e, 1196 | 0xb76d6dda, 1197 | 0x8c8d8d01, 1198 | 0x64d5d5b1, 1199 | 0xd24e4e9c, 1200 | 0xe0a9a949, 1201 | 0xb46c6cd8, 1202 | 0xfa5656ac, 1203 | 0x07f4f4f3, 1204 | 0x25eaeacf, 1205 | 0xaf6565ca, 1206 | 0x8e7a7af4, 1207 | 0xe9aeae47, 1208 | 0x18080810, 1209 | 0xd5baba6f, 1210 | 0x887878f0, 1211 | 0x6f25254a, 1212 | 0x722e2e5c, 1213 | 0x241c1c38, 1214 | 0xf1a6a657, 1215 | 0xc7b4b473, 1216 | 0x51c6c697, 1217 | 0x23e8e8cb, 1218 | 0x7cdddda1, 1219 | 0x9c7474e8, 1220 | 0x211f1f3e, 1221 | 0xdd4b4b96, 1222 | 0xdcbdbd61, 1223 | 0x868b8b0d, 1224 | 0x858a8a0f, 1225 | 0x907070e0, 1226 | 0x423e3e7c, 1227 | 0xc4b5b571, 1228 | 0xaa6666cc, 1229 | 0xd8484890, 1230 | 0x05030306, 1231 | 0x01f6f6f7, 1232 | 0x120e0e1c, 1233 | 0xa36161c2, 1234 | 0x5f35356a, 1235 | 0xf95757ae, 1236 | 0xd0b9b969, 1237 | 0x91868617, 1238 | 0x58c1c199, 1239 | 0x271d1d3a, 1240 | 0xb99e9e27, 1241 | 0x38e1e1d9, 1242 | 0x13f8f8eb, 1243 | 0xb398982b, 1244 | 0x33111122, 1245 | 0xbb6969d2, 1246 | 0x70d9d9a9, 1247 | 0x898e8e07, 1248 | 0xa7949433, 1249 | 0xb69b9b2d, 1250 | 0x221e1e3c, 1251 | 0x92878715, 1252 | 0x20e9e9c9, 1253 | 0x49cece87, 1254 | 0xff5555aa, 1255 | 0x78282850, 1256 | 0x7adfdfa5, 1257 | 0x8f8c8c03, 1258 | 0xf8a1a159, 1259 | 0x80898909, 1260 | 0x170d0d1a, 1261 | 0xdabfbf65, 1262 | 0x31e6e6d7, 1263 | 0xc6424284, 1264 | 0xb86868d0, 1265 | 0xc3414182, 1266 | 0xb0999929, 1267 | 0x772d2d5a, 1268 | 0x110f0f1e, 1269 | 0xcbb0b07b, 1270 | 0xfc5454a8, 1271 | 0xd6bbbb6d, 1272 | 0x3a16162c 1273 | ]; 1274 | 1275 | final _T1 = [ 1276 | 0x6363c6a5, 1277 | 0x7c7cf884, 1278 | 0x7777ee99, 1279 | 0x7b7bf68d, 1280 | 0xf2f2ff0d, 1281 | 0x6b6bd6bd, 1282 | 0x6f6fdeb1, 1283 | 0xc5c59154, 1284 | 0x30306050, 1285 | 0x01010203, 1286 | 0x6767cea9, 1287 | 0x2b2b567d, 1288 | 0xfefee719, 1289 | 0xd7d7b562, 1290 | 0xabab4de6, 1291 | 0x7676ec9a, 1292 | 0xcaca8f45, 1293 | 0x82821f9d, 1294 | 0xc9c98940, 1295 | 0x7d7dfa87, 1296 | 0xfafaef15, 1297 | 0x5959b2eb, 1298 | 0x47478ec9, 1299 | 0xf0f0fb0b, 1300 | 0xadad41ec, 1301 | 0xd4d4b367, 1302 | 0xa2a25ffd, 1303 | 0xafaf45ea, 1304 | 0x9c9c23bf, 1305 | 0xa4a453f7, 1306 | 0x7272e496, 1307 | 0xc0c09b5b, 1308 | 0xb7b775c2, 1309 | 0xfdfde11c, 1310 | 0x93933dae, 1311 | 0x26264c6a, 1312 | 0x36366c5a, 1313 | 0x3f3f7e41, 1314 | 0xf7f7f502, 1315 | 0xcccc834f, 1316 | 0x3434685c, 1317 | 0xa5a551f4, 1318 | 0xe5e5d134, 1319 | 0xf1f1f908, 1320 | 0x7171e293, 1321 | 0xd8d8ab73, 1322 | 0x31316253, 1323 | 0x15152a3f, 1324 | 0x0404080c, 1325 | 0xc7c79552, 1326 | 0x23234665, 1327 | 0xc3c39d5e, 1328 | 0x18183028, 1329 | 0x969637a1, 1330 | 0x05050a0f, 1331 | 0x9a9a2fb5, 1332 | 0x07070e09, 1333 | 0x12122436, 1334 | 0x80801b9b, 1335 | 0xe2e2df3d, 1336 | 0xebebcd26, 1337 | 0x27274e69, 1338 | 0xb2b27fcd, 1339 | 0x7575ea9f, 1340 | 0x0909121b, 1341 | 0x83831d9e, 1342 | 0x2c2c5874, 1343 | 0x1a1a342e, 1344 | 0x1b1b362d, 1345 | 0x6e6edcb2, 1346 | 0x5a5ab4ee, 1347 | 0xa0a05bfb, 1348 | 0x5252a4f6, 1349 | 0x3b3b764d, 1350 | 0xd6d6b761, 1351 | 0xb3b37dce, 1352 | 0x2929527b, 1353 | 0xe3e3dd3e, 1354 | 0x2f2f5e71, 1355 | 0x84841397, 1356 | 0x5353a6f5, 1357 | 0xd1d1b968, 1358 | 0x00000000, 1359 | 0xededc12c, 1360 | 0x20204060, 1361 | 0xfcfce31f, 1362 | 0xb1b179c8, 1363 | 0x5b5bb6ed, 1364 | 0x6a6ad4be, 1365 | 0xcbcb8d46, 1366 | 0xbebe67d9, 1367 | 0x3939724b, 1368 | 0x4a4a94de, 1369 | 0x4c4c98d4, 1370 | 0x5858b0e8, 1371 | 0xcfcf854a, 1372 | 0xd0d0bb6b, 1373 | 0xefefc52a, 1374 | 0xaaaa4fe5, 1375 | 0xfbfbed16, 1376 | 0x434386c5, 1377 | 0x4d4d9ad7, 1378 | 0x33336655, 1379 | 0x85851194, 1380 | 0x45458acf, 1381 | 0xf9f9e910, 1382 | 0x02020406, 1383 | 0x7f7ffe81, 1384 | 0x5050a0f0, 1385 | 0x3c3c7844, 1386 | 0x9f9f25ba, 1387 | 0xa8a84be3, 1388 | 0x5151a2f3, 1389 | 0xa3a35dfe, 1390 | 0x404080c0, 1391 | 0x8f8f058a, 1392 | 0x92923fad, 1393 | 0x9d9d21bc, 1394 | 0x38387048, 1395 | 0xf5f5f104, 1396 | 0xbcbc63df, 1397 | 0xb6b677c1, 1398 | 0xdadaaf75, 1399 | 0x21214263, 1400 | 0x10102030, 1401 | 0xffffe51a, 1402 | 0xf3f3fd0e, 1403 | 0xd2d2bf6d, 1404 | 0xcdcd814c, 1405 | 0x0c0c1814, 1406 | 0x13132635, 1407 | 0xececc32f, 1408 | 0x5f5fbee1, 1409 | 0x979735a2, 1410 | 0x444488cc, 1411 | 0x17172e39, 1412 | 0xc4c49357, 1413 | 0xa7a755f2, 1414 | 0x7e7efc82, 1415 | 0x3d3d7a47, 1416 | 0x6464c8ac, 1417 | 0x5d5dbae7, 1418 | 0x1919322b, 1419 | 0x7373e695, 1420 | 0x6060c0a0, 1421 | 0x81811998, 1422 | 0x4f4f9ed1, 1423 | 0xdcdca37f, 1424 | 0x22224466, 1425 | 0x2a2a547e, 1426 | 0x90903bab, 1427 | 0x88880b83, 1428 | 0x46468cca, 1429 | 0xeeeec729, 1430 | 0xb8b86bd3, 1431 | 0x1414283c, 1432 | 0xdedea779, 1433 | 0x5e5ebce2, 1434 | 0x0b0b161d, 1435 | 0xdbdbad76, 1436 | 0xe0e0db3b, 1437 | 0x32326456, 1438 | 0x3a3a744e, 1439 | 0x0a0a141e, 1440 | 0x494992db, 1441 | 0x06060c0a, 1442 | 0x2424486c, 1443 | 0x5c5cb8e4, 1444 | 0xc2c29f5d, 1445 | 0xd3d3bd6e, 1446 | 0xacac43ef, 1447 | 0x6262c4a6, 1448 | 0x919139a8, 1449 | 0x959531a4, 1450 | 0xe4e4d337, 1451 | 0x7979f28b, 1452 | 0xe7e7d532, 1453 | 0xc8c88b43, 1454 | 0x37376e59, 1455 | 0x6d6ddab7, 1456 | 0x8d8d018c, 1457 | 0xd5d5b164, 1458 | 0x4e4e9cd2, 1459 | 0xa9a949e0, 1460 | 0x6c6cd8b4, 1461 | 0x5656acfa, 1462 | 0xf4f4f307, 1463 | 0xeaeacf25, 1464 | 0x6565caaf, 1465 | 0x7a7af48e, 1466 | 0xaeae47e9, 1467 | 0x08081018, 1468 | 0xbaba6fd5, 1469 | 0x7878f088, 1470 | 0x25254a6f, 1471 | 0x2e2e5c72, 1472 | 0x1c1c3824, 1473 | 0xa6a657f1, 1474 | 0xb4b473c7, 1475 | 0xc6c69751, 1476 | 0xe8e8cb23, 1477 | 0xdddda17c, 1478 | 0x7474e89c, 1479 | 0x1f1f3e21, 1480 | 0x4b4b96dd, 1481 | 0xbdbd61dc, 1482 | 0x8b8b0d86, 1483 | 0x8a8a0f85, 1484 | 0x7070e090, 1485 | 0x3e3e7c42, 1486 | 0xb5b571c4, 1487 | 0x6666ccaa, 1488 | 0x484890d8, 1489 | 0x03030605, 1490 | 0xf6f6f701, 1491 | 0x0e0e1c12, 1492 | 0x6161c2a3, 1493 | 0x35356a5f, 1494 | 0x5757aef9, 1495 | 0xb9b969d0, 1496 | 0x86861791, 1497 | 0xc1c19958, 1498 | 0x1d1d3a27, 1499 | 0x9e9e27b9, 1500 | 0xe1e1d938, 1501 | 0xf8f8eb13, 1502 | 0x98982bb3, 1503 | 0x11112233, 1504 | 0x6969d2bb, 1505 | 0xd9d9a970, 1506 | 0x8e8e0789, 1507 | 0x949433a7, 1508 | 0x9b9b2db6, 1509 | 0x1e1e3c22, 1510 | 0x87871592, 1511 | 0xe9e9c920, 1512 | 0xcece8749, 1513 | 0x5555aaff, 1514 | 0x28285078, 1515 | 0xdfdfa57a, 1516 | 0x8c8c038f, 1517 | 0xa1a159f8, 1518 | 0x89890980, 1519 | 0x0d0d1a17, 1520 | 0xbfbf65da, 1521 | 0xe6e6d731, 1522 | 0x424284c6, 1523 | 0x6868d0b8, 1524 | 0x414182c3, 1525 | 0x999929b0, 1526 | 0x2d2d5a77, 1527 | 0x0f0f1e11, 1528 | 0xb0b07bcb, 1529 | 0x5454a8fc, 1530 | 0xbbbb6dd6, 1531 | 0x16162c3a 1532 | ]; 1533 | 1534 | final _T2 = [ 1535 | 0x63c6a563, 1536 | 0x7cf8847c, 1537 | 0x77ee9977, 1538 | 0x7bf68d7b, 1539 | 0xf2ff0df2, 1540 | 0x6bd6bd6b, 1541 | 0x6fdeb16f, 1542 | 0xc59154c5, 1543 | 0x30605030, 1544 | 0x01020301, 1545 | 0x67cea967, 1546 | 0x2b567d2b, 1547 | 0xfee719fe, 1548 | 0xd7b562d7, 1549 | 0xab4de6ab, 1550 | 0x76ec9a76, 1551 | 0xca8f45ca, 1552 | 0x821f9d82, 1553 | 0xc98940c9, 1554 | 0x7dfa877d, 1555 | 0xfaef15fa, 1556 | 0x59b2eb59, 1557 | 0x478ec947, 1558 | 0xf0fb0bf0, 1559 | 0xad41ecad, 1560 | 0xd4b367d4, 1561 | 0xa25ffda2, 1562 | 0xaf45eaaf, 1563 | 0x9c23bf9c, 1564 | 0xa453f7a4, 1565 | 0x72e49672, 1566 | 0xc09b5bc0, 1567 | 0xb775c2b7, 1568 | 0xfde11cfd, 1569 | 0x933dae93, 1570 | 0x264c6a26, 1571 | 0x366c5a36, 1572 | 0x3f7e413f, 1573 | 0xf7f502f7, 1574 | 0xcc834fcc, 1575 | 0x34685c34, 1576 | 0xa551f4a5, 1577 | 0xe5d134e5, 1578 | 0xf1f908f1, 1579 | 0x71e29371, 1580 | 0xd8ab73d8, 1581 | 0x31625331, 1582 | 0x152a3f15, 1583 | 0x04080c04, 1584 | 0xc79552c7, 1585 | 0x23466523, 1586 | 0xc39d5ec3, 1587 | 0x18302818, 1588 | 0x9637a196, 1589 | 0x050a0f05, 1590 | 0x9a2fb59a, 1591 | 0x070e0907, 1592 | 0x12243612, 1593 | 0x801b9b80, 1594 | 0xe2df3de2, 1595 | 0xebcd26eb, 1596 | 0x274e6927, 1597 | 0xb27fcdb2, 1598 | 0x75ea9f75, 1599 | 0x09121b09, 1600 | 0x831d9e83, 1601 | 0x2c58742c, 1602 | 0x1a342e1a, 1603 | 0x1b362d1b, 1604 | 0x6edcb26e, 1605 | 0x5ab4ee5a, 1606 | 0xa05bfba0, 1607 | 0x52a4f652, 1608 | 0x3b764d3b, 1609 | 0xd6b761d6, 1610 | 0xb37dceb3, 1611 | 0x29527b29, 1612 | 0xe3dd3ee3, 1613 | 0x2f5e712f, 1614 | 0x84139784, 1615 | 0x53a6f553, 1616 | 0xd1b968d1, 1617 | 0x00000000, 1618 | 0xedc12ced, 1619 | 0x20406020, 1620 | 0xfce31ffc, 1621 | 0xb179c8b1, 1622 | 0x5bb6ed5b, 1623 | 0x6ad4be6a, 1624 | 0xcb8d46cb, 1625 | 0xbe67d9be, 1626 | 0x39724b39, 1627 | 0x4a94de4a, 1628 | 0x4c98d44c, 1629 | 0x58b0e858, 1630 | 0xcf854acf, 1631 | 0xd0bb6bd0, 1632 | 0xefc52aef, 1633 | 0xaa4fe5aa, 1634 | 0xfbed16fb, 1635 | 0x4386c543, 1636 | 0x4d9ad74d, 1637 | 0x33665533, 1638 | 0x85119485, 1639 | 0x458acf45, 1640 | 0xf9e910f9, 1641 | 0x02040602, 1642 | 0x7ffe817f, 1643 | 0x50a0f050, 1644 | 0x3c78443c, 1645 | 0x9f25ba9f, 1646 | 0xa84be3a8, 1647 | 0x51a2f351, 1648 | 0xa35dfea3, 1649 | 0x4080c040, 1650 | 0x8f058a8f, 1651 | 0x923fad92, 1652 | 0x9d21bc9d, 1653 | 0x38704838, 1654 | 0xf5f104f5, 1655 | 0xbc63dfbc, 1656 | 0xb677c1b6, 1657 | 0xdaaf75da, 1658 | 0x21426321, 1659 | 0x10203010, 1660 | 0xffe51aff, 1661 | 0xf3fd0ef3, 1662 | 0xd2bf6dd2, 1663 | 0xcd814ccd, 1664 | 0x0c18140c, 1665 | 0x13263513, 1666 | 0xecc32fec, 1667 | 0x5fbee15f, 1668 | 0x9735a297, 1669 | 0x4488cc44, 1670 | 0x172e3917, 1671 | 0xc49357c4, 1672 | 0xa755f2a7, 1673 | 0x7efc827e, 1674 | 0x3d7a473d, 1675 | 0x64c8ac64, 1676 | 0x5dbae75d, 1677 | 0x19322b19, 1678 | 0x73e69573, 1679 | 0x60c0a060, 1680 | 0x81199881, 1681 | 0x4f9ed14f, 1682 | 0xdca37fdc, 1683 | 0x22446622, 1684 | 0x2a547e2a, 1685 | 0x903bab90, 1686 | 0x880b8388, 1687 | 0x468cca46, 1688 | 0xeec729ee, 1689 | 0xb86bd3b8, 1690 | 0x14283c14, 1691 | 0xdea779de, 1692 | 0x5ebce25e, 1693 | 0x0b161d0b, 1694 | 0xdbad76db, 1695 | 0xe0db3be0, 1696 | 0x32645632, 1697 | 0x3a744e3a, 1698 | 0x0a141e0a, 1699 | 0x4992db49, 1700 | 0x060c0a06, 1701 | 0x24486c24, 1702 | 0x5cb8e45c, 1703 | 0xc29f5dc2, 1704 | 0xd3bd6ed3, 1705 | 0xac43efac, 1706 | 0x62c4a662, 1707 | 0x9139a891, 1708 | 0x9531a495, 1709 | 0xe4d337e4, 1710 | 0x79f28b79, 1711 | 0xe7d532e7, 1712 | 0xc88b43c8, 1713 | 0x376e5937, 1714 | 0x6ddab76d, 1715 | 0x8d018c8d, 1716 | 0xd5b164d5, 1717 | 0x4e9cd24e, 1718 | 0xa949e0a9, 1719 | 0x6cd8b46c, 1720 | 0x56acfa56, 1721 | 0xf4f307f4, 1722 | 0xeacf25ea, 1723 | 0x65caaf65, 1724 | 0x7af48e7a, 1725 | 0xae47e9ae, 1726 | 0x08101808, 1727 | 0xba6fd5ba, 1728 | 0x78f08878, 1729 | 0x254a6f25, 1730 | 0x2e5c722e, 1731 | 0x1c38241c, 1732 | 0xa657f1a6, 1733 | 0xb473c7b4, 1734 | 0xc69751c6, 1735 | 0xe8cb23e8, 1736 | 0xdda17cdd, 1737 | 0x74e89c74, 1738 | 0x1f3e211f, 1739 | 0x4b96dd4b, 1740 | 0xbd61dcbd, 1741 | 0x8b0d868b, 1742 | 0x8a0f858a, 1743 | 0x70e09070, 1744 | 0x3e7c423e, 1745 | 0xb571c4b5, 1746 | 0x66ccaa66, 1747 | 0x4890d848, 1748 | 0x03060503, 1749 | 0xf6f701f6, 1750 | 0x0e1c120e, 1751 | 0x61c2a361, 1752 | 0x356a5f35, 1753 | 0x57aef957, 1754 | 0xb969d0b9, 1755 | 0x86179186, 1756 | 0xc19958c1, 1757 | 0x1d3a271d, 1758 | 0x9e27b99e, 1759 | 0xe1d938e1, 1760 | 0xf8eb13f8, 1761 | 0x982bb398, 1762 | 0x11223311, 1763 | 0x69d2bb69, 1764 | 0xd9a970d9, 1765 | 0x8e07898e, 1766 | 0x9433a794, 1767 | 0x9b2db69b, 1768 | 0x1e3c221e, 1769 | 0x87159287, 1770 | 0xe9c920e9, 1771 | 0xce8749ce, 1772 | 0x55aaff55, 1773 | 0x28507828, 1774 | 0xdfa57adf, 1775 | 0x8c038f8c, 1776 | 0xa159f8a1, 1777 | 0x89098089, 1778 | 0x0d1a170d, 1779 | 0xbf65dabf, 1780 | 0xe6d731e6, 1781 | 0x4284c642, 1782 | 0x68d0b868, 1783 | 0x4182c341, 1784 | 0x9929b099, 1785 | 0x2d5a772d, 1786 | 0x0f1e110f, 1787 | 0xb07bcbb0, 1788 | 0x54a8fc54, 1789 | 0xbb6dd6bb, 1790 | 0x162c3a16 1791 | ]; 1792 | 1793 | final _T3 = [ 1794 | 0xc6a56363, 1795 | 0xf8847c7c, 1796 | 0xee997777, 1797 | 0xf68d7b7b, 1798 | 0xff0df2f2, 1799 | 0xd6bd6b6b, 1800 | 0xdeb16f6f, 1801 | 0x9154c5c5, 1802 | 0x60503030, 1803 | 0x02030101, 1804 | 0xcea96767, 1805 | 0x567d2b2b, 1806 | 0xe719fefe, 1807 | 0xb562d7d7, 1808 | 0x4de6abab, 1809 | 0xec9a7676, 1810 | 0x8f45caca, 1811 | 0x1f9d8282, 1812 | 0x8940c9c9, 1813 | 0xfa877d7d, 1814 | 0xef15fafa, 1815 | 0xb2eb5959, 1816 | 0x8ec94747, 1817 | 0xfb0bf0f0, 1818 | 0x41ecadad, 1819 | 0xb367d4d4, 1820 | 0x5ffda2a2, 1821 | 0x45eaafaf, 1822 | 0x23bf9c9c, 1823 | 0x53f7a4a4, 1824 | 0xe4967272, 1825 | 0x9b5bc0c0, 1826 | 0x75c2b7b7, 1827 | 0xe11cfdfd, 1828 | 0x3dae9393, 1829 | 0x4c6a2626, 1830 | 0x6c5a3636, 1831 | 0x7e413f3f, 1832 | 0xf502f7f7, 1833 | 0x834fcccc, 1834 | 0x685c3434, 1835 | 0x51f4a5a5, 1836 | 0xd134e5e5, 1837 | 0xf908f1f1, 1838 | 0xe2937171, 1839 | 0xab73d8d8, 1840 | 0x62533131, 1841 | 0x2a3f1515, 1842 | 0x080c0404, 1843 | 0x9552c7c7, 1844 | 0x46652323, 1845 | 0x9d5ec3c3, 1846 | 0x30281818, 1847 | 0x37a19696, 1848 | 0x0a0f0505, 1849 | 0x2fb59a9a, 1850 | 0x0e090707, 1851 | 0x24361212, 1852 | 0x1b9b8080, 1853 | 0xdf3de2e2, 1854 | 0xcd26ebeb, 1855 | 0x4e692727, 1856 | 0x7fcdb2b2, 1857 | 0xea9f7575, 1858 | 0x121b0909, 1859 | 0x1d9e8383, 1860 | 0x58742c2c, 1861 | 0x342e1a1a, 1862 | 0x362d1b1b, 1863 | 0xdcb26e6e, 1864 | 0xb4ee5a5a, 1865 | 0x5bfba0a0, 1866 | 0xa4f65252, 1867 | 0x764d3b3b, 1868 | 0xb761d6d6, 1869 | 0x7dceb3b3, 1870 | 0x527b2929, 1871 | 0xdd3ee3e3, 1872 | 0x5e712f2f, 1873 | 0x13978484, 1874 | 0xa6f55353, 1875 | 0xb968d1d1, 1876 | 0x00000000, 1877 | 0xc12ceded, 1878 | 0x40602020, 1879 | 0xe31ffcfc, 1880 | 0x79c8b1b1, 1881 | 0xb6ed5b5b, 1882 | 0xd4be6a6a, 1883 | 0x8d46cbcb, 1884 | 0x67d9bebe, 1885 | 0x724b3939, 1886 | 0x94de4a4a, 1887 | 0x98d44c4c, 1888 | 0xb0e85858, 1889 | 0x854acfcf, 1890 | 0xbb6bd0d0, 1891 | 0xc52aefef, 1892 | 0x4fe5aaaa, 1893 | 0xed16fbfb, 1894 | 0x86c54343, 1895 | 0x9ad74d4d, 1896 | 0x66553333, 1897 | 0x11948585, 1898 | 0x8acf4545, 1899 | 0xe910f9f9, 1900 | 0x04060202, 1901 | 0xfe817f7f, 1902 | 0xa0f05050, 1903 | 0x78443c3c, 1904 | 0x25ba9f9f, 1905 | 0x4be3a8a8, 1906 | 0xa2f35151, 1907 | 0x5dfea3a3, 1908 | 0x80c04040, 1909 | 0x058a8f8f, 1910 | 0x3fad9292, 1911 | 0x21bc9d9d, 1912 | 0x70483838, 1913 | 0xf104f5f5, 1914 | 0x63dfbcbc, 1915 | 0x77c1b6b6, 1916 | 0xaf75dada, 1917 | 0x42632121, 1918 | 0x20301010, 1919 | 0xe51affff, 1920 | 0xfd0ef3f3, 1921 | 0xbf6dd2d2, 1922 | 0x814ccdcd, 1923 | 0x18140c0c, 1924 | 0x26351313, 1925 | 0xc32fecec, 1926 | 0xbee15f5f, 1927 | 0x35a29797, 1928 | 0x88cc4444, 1929 | 0x2e391717, 1930 | 0x9357c4c4, 1931 | 0x55f2a7a7, 1932 | 0xfc827e7e, 1933 | 0x7a473d3d, 1934 | 0xc8ac6464, 1935 | 0xbae75d5d, 1936 | 0x322b1919, 1937 | 0xe6957373, 1938 | 0xc0a06060, 1939 | 0x19988181, 1940 | 0x9ed14f4f, 1941 | 0xa37fdcdc, 1942 | 0x44662222, 1943 | 0x547e2a2a, 1944 | 0x3bab9090, 1945 | 0x0b838888, 1946 | 0x8cca4646, 1947 | 0xc729eeee, 1948 | 0x6bd3b8b8, 1949 | 0x283c1414, 1950 | 0xa779dede, 1951 | 0xbce25e5e, 1952 | 0x161d0b0b, 1953 | 0xad76dbdb, 1954 | 0xdb3be0e0, 1955 | 0x64563232, 1956 | 0x744e3a3a, 1957 | 0x141e0a0a, 1958 | 0x92db4949, 1959 | 0x0c0a0606, 1960 | 0x486c2424, 1961 | 0xb8e45c5c, 1962 | 0x9f5dc2c2, 1963 | 0xbd6ed3d3, 1964 | 0x43efacac, 1965 | 0xc4a66262, 1966 | 0x39a89191, 1967 | 0x31a49595, 1968 | 0xd337e4e4, 1969 | 0xf28b7979, 1970 | 0xd532e7e7, 1971 | 0x8b43c8c8, 1972 | 0x6e593737, 1973 | 0xdab76d6d, 1974 | 0x018c8d8d, 1975 | 0xb164d5d5, 1976 | 0x9cd24e4e, 1977 | 0x49e0a9a9, 1978 | 0xd8b46c6c, 1979 | 0xacfa5656, 1980 | 0xf307f4f4, 1981 | 0xcf25eaea, 1982 | 0xcaaf6565, 1983 | 0xf48e7a7a, 1984 | 0x47e9aeae, 1985 | 0x10180808, 1986 | 0x6fd5baba, 1987 | 0xf0887878, 1988 | 0x4a6f2525, 1989 | 0x5c722e2e, 1990 | 0x38241c1c, 1991 | 0x57f1a6a6, 1992 | 0x73c7b4b4, 1993 | 0x9751c6c6, 1994 | 0xcb23e8e8, 1995 | 0xa17cdddd, 1996 | 0xe89c7474, 1997 | 0x3e211f1f, 1998 | 0x96dd4b4b, 1999 | 0x61dcbdbd, 2000 | 0x0d868b8b, 2001 | 0x0f858a8a, 2002 | 0xe0907070, 2003 | 0x7c423e3e, 2004 | 0x71c4b5b5, 2005 | 0xccaa6666, 2006 | 0x90d84848, 2007 | 0x06050303, 2008 | 0xf701f6f6, 2009 | 0x1c120e0e, 2010 | 0xc2a36161, 2011 | 0x6a5f3535, 2012 | 0xaef95757, 2013 | 0x69d0b9b9, 2014 | 0x17918686, 2015 | 0x9958c1c1, 2016 | 0x3a271d1d, 2017 | 0x27b99e9e, 2018 | 0xd938e1e1, 2019 | 0xeb13f8f8, 2020 | 0x2bb39898, 2021 | 0x22331111, 2022 | 0xd2bb6969, 2023 | 0xa970d9d9, 2024 | 0x07898e8e, 2025 | 0x33a79494, 2026 | 0x2db69b9b, 2027 | 0x3c221e1e, 2028 | 0x15928787, 2029 | 0xc920e9e9, 2030 | 0x8749cece, 2031 | 0xaaff5555, 2032 | 0x50782828, 2033 | 0xa57adfdf, 2034 | 0x038f8c8c, 2035 | 0x59f8a1a1, 2036 | 0x09808989, 2037 | 0x1a170d0d, 2038 | 0x65dabfbf, 2039 | 0xd731e6e6, 2040 | 0x84c64242, 2041 | 0xd0b86868, 2042 | 0x82c34141, 2043 | 0x29b09999, 2044 | 0x5a772d2d, 2045 | 0x1e110f0f, 2046 | 0x7bcbb0b0, 2047 | 0xa8fc5454, 2048 | 0x6dd6bbbb, 2049 | 0x2c3a1616 2050 | ]; 2051 | 2052 | final _Tinv0 = [ 2053 | 0x50a7f451, 2054 | 0x5365417e, 2055 | 0xc3a4171a, 2056 | 0x965e273a, 2057 | 0xcb6bab3b, 2058 | 0xf1459d1f, 2059 | 0xab58faac, 2060 | 0x9303e34b, 2061 | 0x55fa3020, 2062 | 0xf66d76ad, 2063 | 0x9176cc88, 2064 | 0x254c02f5, 2065 | 0xfcd7e54f, 2066 | 0xd7cb2ac5, 2067 | 0x80443526, 2068 | 0x8fa362b5, 2069 | 0x495ab1de, 2070 | 0x671bba25, 2071 | 0x980eea45, 2072 | 0xe1c0fe5d, 2073 | 0x02752fc3, 2074 | 0x12f04c81, 2075 | 0xa397468d, 2076 | 0xc6f9d36b, 2077 | 0xe75f8f03, 2078 | 0x959c9215, 2079 | 0xeb7a6dbf, 2080 | 0xda595295, 2081 | 0x2d83bed4, 2082 | 0xd3217458, 2083 | 0x2969e049, 2084 | 0x44c8c98e, 2085 | 0x6a89c275, 2086 | 0x78798ef4, 2087 | 0x6b3e5899, 2088 | 0xdd71b927, 2089 | 0xb64fe1be, 2090 | 0x17ad88f0, 2091 | 0x66ac20c9, 2092 | 0xb43ace7d, 2093 | 0x184adf63, 2094 | 0x82311ae5, 2095 | 0x60335197, 2096 | 0x457f5362, 2097 | 0xe07764b1, 2098 | 0x84ae6bbb, 2099 | 0x1ca081fe, 2100 | 0x942b08f9, 2101 | 0x58684870, 2102 | 0x19fd458f, 2103 | 0x876cde94, 2104 | 0xb7f87b52, 2105 | 0x23d373ab, 2106 | 0xe2024b72, 2107 | 0x578f1fe3, 2108 | 0x2aab5566, 2109 | 0x0728ebb2, 2110 | 0x03c2b52f, 2111 | 0x9a7bc586, 2112 | 0xa50837d3, 2113 | 0xf2872830, 2114 | 0xb2a5bf23, 2115 | 0xba6a0302, 2116 | 0x5c8216ed, 2117 | 0x2b1ccf8a, 2118 | 0x92b479a7, 2119 | 0xf0f207f3, 2120 | 0xa1e2694e, 2121 | 0xcdf4da65, 2122 | 0xd5be0506, 2123 | 0x1f6234d1, 2124 | 0x8afea6c4, 2125 | 0x9d532e34, 2126 | 0xa055f3a2, 2127 | 0x32e18a05, 2128 | 0x75ebf6a4, 2129 | 0x39ec830b, 2130 | 0xaaef6040, 2131 | 0x069f715e, 2132 | 0x51106ebd, 2133 | 0xf98a213e, 2134 | 0x3d06dd96, 2135 | 0xae053edd, 2136 | 0x46bde64d, 2137 | 0xb58d5491, 2138 | 0x055dc471, 2139 | 0x6fd40604, 2140 | 0xff155060, 2141 | 0x24fb9819, 2142 | 0x97e9bdd6, 2143 | 0xcc434089, 2144 | 0x779ed967, 2145 | 0xbd42e8b0, 2146 | 0x888b8907, 2147 | 0x385b19e7, 2148 | 0xdbeec879, 2149 | 0x470a7ca1, 2150 | 0xe90f427c, 2151 | 0xc91e84f8, 2152 | 0x00000000, 2153 | 0x83868009, 2154 | 0x48ed2b32, 2155 | 0xac70111e, 2156 | 0x4e725a6c, 2157 | 0xfbff0efd, 2158 | 0x5638850f, 2159 | 0x1ed5ae3d, 2160 | 0x27392d36, 2161 | 0x64d90f0a, 2162 | 0x21a65c68, 2163 | 0xd1545b9b, 2164 | 0x3a2e3624, 2165 | 0xb1670a0c, 2166 | 0x0fe75793, 2167 | 0xd296eeb4, 2168 | 0x9e919b1b, 2169 | 0x4fc5c080, 2170 | 0xa220dc61, 2171 | 0x694b775a, 2172 | 0x161a121c, 2173 | 0x0aba93e2, 2174 | 0xe52aa0c0, 2175 | 0x43e0223c, 2176 | 0x1d171b12, 2177 | 0x0b0d090e, 2178 | 0xadc78bf2, 2179 | 0xb9a8b62d, 2180 | 0xc8a91e14, 2181 | 0x8519f157, 2182 | 0x4c0775af, 2183 | 0xbbdd99ee, 2184 | 0xfd607fa3, 2185 | 0x9f2601f7, 2186 | 0xbcf5725c, 2187 | 0xc53b6644, 2188 | 0x347efb5b, 2189 | 0x7629438b, 2190 | 0xdcc623cb, 2191 | 0x68fcedb6, 2192 | 0x63f1e4b8, 2193 | 0xcadc31d7, 2194 | 0x10856342, 2195 | 0x40229713, 2196 | 0x2011c684, 2197 | 0x7d244a85, 2198 | 0xf83dbbd2, 2199 | 0x1132f9ae, 2200 | 0x6da129c7, 2201 | 0x4b2f9e1d, 2202 | 0xf330b2dc, 2203 | 0xec52860d, 2204 | 0xd0e3c177, 2205 | 0x6c16b32b, 2206 | 0x99b970a9, 2207 | 0xfa489411, 2208 | 0x2264e947, 2209 | 0xc48cfca8, 2210 | 0x1a3ff0a0, 2211 | 0xd82c7d56, 2212 | 0xef903322, 2213 | 0xc74e4987, 2214 | 0xc1d138d9, 2215 | 0xfea2ca8c, 2216 | 0x360bd498, 2217 | 0xcf81f5a6, 2218 | 0x28de7aa5, 2219 | 0x268eb7da, 2220 | 0xa4bfad3f, 2221 | 0xe49d3a2c, 2222 | 0x0d927850, 2223 | 0x9bcc5f6a, 2224 | 0x62467e54, 2225 | 0xc2138df6, 2226 | 0xe8b8d890, 2227 | 0x5ef7392e, 2228 | 0xf5afc382, 2229 | 0xbe805d9f, 2230 | 0x7c93d069, 2231 | 0xa92dd56f, 2232 | 0xb31225cf, 2233 | 0x3b99acc8, 2234 | 0xa77d1810, 2235 | 0x6e639ce8, 2236 | 0x7bbb3bdb, 2237 | 0x097826cd, 2238 | 0xf418596e, 2239 | 0x01b79aec, 2240 | 0xa89a4f83, 2241 | 0x656e95e6, 2242 | 0x7ee6ffaa, 2243 | 0x08cfbc21, 2244 | 0xe6e815ef, 2245 | 0xd99be7ba, 2246 | 0xce366f4a, 2247 | 0xd4099fea, 2248 | 0xd67cb029, 2249 | 0xafb2a431, 2250 | 0x31233f2a, 2251 | 0x3094a5c6, 2252 | 0xc066a235, 2253 | 0x37bc4e74, 2254 | 0xa6ca82fc, 2255 | 0xb0d090e0, 2256 | 0x15d8a733, 2257 | 0x4a9804f1, 2258 | 0xf7daec41, 2259 | 0x0e50cd7f, 2260 | 0x2ff69117, 2261 | 0x8dd64d76, 2262 | 0x4db0ef43, 2263 | 0x544daacc, 2264 | 0xdf0496e4, 2265 | 0xe3b5d19e, 2266 | 0x1b886a4c, 2267 | 0xb81f2cc1, 2268 | 0x7f516546, 2269 | 0x04ea5e9d, 2270 | 0x5d358c01, 2271 | 0x737487fa, 2272 | 0x2e410bfb, 2273 | 0x5a1d67b3, 2274 | 0x52d2db92, 2275 | 0x335610e9, 2276 | 0x1347d66d, 2277 | 0x8c61d79a, 2278 | 0x7a0ca137, 2279 | 0x8e14f859, 2280 | 0x893c13eb, 2281 | 0xee27a9ce, 2282 | 0x35c961b7, 2283 | 0xede51ce1, 2284 | 0x3cb1477a, 2285 | 0x59dfd29c, 2286 | 0x3f73f255, 2287 | 0x79ce1418, 2288 | 0xbf37c773, 2289 | 0xeacdf753, 2290 | 0x5baafd5f, 2291 | 0x146f3ddf, 2292 | 0x86db4478, 2293 | 0x81f3afca, 2294 | 0x3ec468b9, 2295 | 0x2c342438, 2296 | 0x5f40a3c2, 2297 | 0x72c31d16, 2298 | 0x0c25e2bc, 2299 | 0x8b493c28, 2300 | 0x41950dff, 2301 | 0x7101a839, 2302 | 0xdeb30c08, 2303 | 0x9ce4b4d8, 2304 | 0x90c15664, 2305 | 0x6184cb7b, 2306 | 0x70b632d5, 2307 | 0x745c6c48, 2308 | 0x4257b8d0 2309 | ]; 2310 | 2311 | final _Tinv1 = [ 2312 | 0xa7f45150, 2313 | 0x65417e53, 2314 | 0xa4171ac3, 2315 | 0x5e273a96, 2316 | 0x6bab3bcb, 2317 | 0x459d1ff1, 2318 | 0x58faacab, 2319 | 0x03e34b93, 2320 | 0xfa302055, 2321 | 0x6d76adf6, 2322 | 0x76cc8891, 2323 | 0x4c02f525, 2324 | 0xd7e54ffc, 2325 | 0xcb2ac5d7, 2326 | 0x44352680, 2327 | 0xa362b58f, 2328 | 0x5ab1de49, 2329 | 0x1bba2567, 2330 | 0x0eea4598, 2331 | 0xc0fe5de1, 2332 | 0x752fc302, 2333 | 0xf04c8112, 2334 | 0x97468da3, 2335 | 0xf9d36bc6, 2336 | 0x5f8f03e7, 2337 | 0x9c921595, 2338 | 0x7a6dbfeb, 2339 | 0x595295da, 2340 | 0x83bed42d, 2341 | 0x217458d3, 2342 | 0x69e04929, 2343 | 0xc8c98e44, 2344 | 0x89c2756a, 2345 | 0x798ef478, 2346 | 0x3e58996b, 2347 | 0x71b927dd, 2348 | 0x4fe1beb6, 2349 | 0xad88f017, 2350 | 0xac20c966, 2351 | 0x3ace7db4, 2352 | 0x4adf6318, 2353 | 0x311ae582, 2354 | 0x33519760, 2355 | 0x7f536245, 2356 | 0x7764b1e0, 2357 | 0xae6bbb84, 2358 | 0xa081fe1c, 2359 | 0x2b08f994, 2360 | 0x68487058, 2361 | 0xfd458f19, 2362 | 0x6cde9487, 2363 | 0xf87b52b7, 2364 | 0xd373ab23, 2365 | 0x024b72e2, 2366 | 0x8f1fe357, 2367 | 0xab55662a, 2368 | 0x28ebb207, 2369 | 0xc2b52f03, 2370 | 0x7bc5869a, 2371 | 0x0837d3a5, 2372 | 0x872830f2, 2373 | 0xa5bf23b2, 2374 | 0x6a0302ba, 2375 | 0x8216ed5c, 2376 | 0x1ccf8a2b, 2377 | 0xb479a792, 2378 | 0xf207f3f0, 2379 | 0xe2694ea1, 2380 | 0xf4da65cd, 2381 | 0xbe0506d5, 2382 | 0x6234d11f, 2383 | 0xfea6c48a, 2384 | 0x532e349d, 2385 | 0x55f3a2a0, 2386 | 0xe18a0532, 2387 | 0xebf6a475, 2388 | 0xec830b39, 2389 | 0xef6040aa, 2390 | 0x9f715e06, 2391 | 0x106ebd51, 2392 | 0x8a213ef9, 2393 | 0x06dd963d, 2394 | 0x053eddae, 2395 | 0xbde64d46, 2396 | 0x8d5491b5, 2397 | 0x5dc47105, 2398 | 0xd406046f, 2399 | 0x155060ff, 2400 | 0xfb981924, 2401 | 0xe9bdd697, 2402 | 0x434089cc, 2403 | 0x9ed96777, 2404 | 0x42e8b0bd, 2405 | 0x8b890788, 2406 | 0x5b19e738, 2407 | 0xeec879db, 2408 | 0x0a7ca147, 2409 | 0x0f427ce9, 2410 | 0x1e84f8c9, 2411 | 0x00000000, 2412 | 0x86800983, 2413 | 0xed2b3248, 2414 | 0x70111eac, 2415 | 0x725a6c4e, 2416 | 0xff0efdfb, 2417 | 0x38850f56, 2418 | 0xd5ae3d1e, 2419 | 0x392d3627, 2420 | 0xd90f0a64, 2421 | 0xa65c6821, 2422 | 0x545b9bd1, 2423 | 0x2e36243a, 2424 | 0x670a0cb1, 2425 | 0xe757930f, 2426 | 0x96eeb4d2, 2427 | 0x919b1b9e, 2428 | 0xc5c0804f, 2429 | 0x20dc61a2, 2430 | 0x4b775a69, 2431 | 0x1a121c16, 2432 | 0xba93e20a, 2433 | 0x2aa0c0e5, 2434 | 0xe0223c43, 2435 | 0x171b121d, 2436 | 0x0d090e0b, 2437 | 0xc78bf2ad, 2438 | 0xa8b62db9, 2439 | 0xa91e14c8, 2440 | 0x19f15785, 2441 | 0x0775af4c, 2442 | 0xdd99eebb, 2443 | 0x607fa3fd, 2444 | 0x2601f79f, 2445 | 0xf5725cbc, 2446 | 0x3b6644c5, 2447 | 0x7efb5b34, 2448 | 0x29438b76, 2449 | 0xc623cbdc, 2450 | 0xfcedb668, 2451 | 0xf1e4b863, 2452 | 0xdc31d7ca, 2453 | 0x85634210, 2454 | 0x22971340, 2455 | 0x11c68420, 2456 | 0x244a857d, 2457 | 0x3dbbd2f8, 2458 | 0x32f9ae11, 2459 | 0xa129c76d, 2460 | 0x2f9e1d4b, 2461 | 0x30b2dcf3, 2462 | 0x52860dec, 2463 | 0xe3c177d0, 2464 | 0x16b32b6c, 2465 | 0xb970a999, 2466 | 0x489411fa, 2467 | 0x64e94722, 2468 | 0x8cfca8c4, 2469 | 0x3ff0a01a, 2470 | 0x2c7d56d8, 2471 | 0x903322ef, 2472 | 0x4e4987c7, 2473 | 0xd138d9c1, 2474 | 0xa2ca8cfe, 2475 | 0x0bd49836, 2476 | 0x81f5a6cf, 2477 | 0xde7aa528, 2478 | 0x8eb7da26, 2479 | 0xbfad3fa4, 2480 | 0x9d3a2ce4, 2481 | 0x9278500d, 2482 | 0xcc5f6a9b, 2483 | 0x467e5462, 2484 | 0x138df6c2, 2485 | 0xb8d890e8, 2486 | 0xf7392e5e, 2487 | 0xafc382f5, 2488 | 0x805d9fbe, 2489 | 0x93d0697c, 2490 | 0x2dd56fa9, 2491 | 0x1225cfb3, 2492 | 0x99acc83b, 2493 | 0x7d1810a7, 2494 | 0x639ce86e, 2495 | 0xbb3bdb7b, 2496 | 0x7826cd09, 2497 | 0x18596ef4, 2498 | 0xb79aec01, 2499 | 0x9a4f83a8, 2500 | 0x6e95e665, 2501 | 0xe6ffaa7e, 2502 | 0xcfbc2108, 2503 | 0xe815efe6, 2504 | 0x9be7bad9, 2505 | 0x366f4ace, 2506 | 0x099fead4, 2507 | 0x7cb029d6, 2508 | 0xb2a431af, 2509 | 0x233f2a31, 2510 | 0x94a5c630, 2511 | 0x66a235c0, 2512 | 0xbc4e7437, 2513 | 0xca82fca6, 2514 | 0xd090e0b0, 2515 | 0xd8a73315, 2516 | 0x9804f14a, 2517 | 0xdaec41f7, 2518 | 0x50cd7f0e, 2519 | 0xf691172f, 2520 | 0xd64d768d, 2521 | 0xb0ef434d, 2522 | 0x4daacc54, 2523 | 0x0496e4df, 2524 | 0xb5d19ee3, 2525 | 0x886a4c1b, 2526 | 0x1f2cc1b8, 2527 | 0x5165467f, 2528 | 0xea5e9d04, 2529 | 0x358c015d, 2530 | 0x7487fa73, 2531 | 0x410bfb2e, 2532 | 0x1d67b35a, 2533 | 0xd2db9252, 2534 | 0x5610e933, 2535 | 0x47d66d13, 2536 | 0x61d79a8c, 2537 | 0x0ca1377a, 2538 | 0x14f8598e, 2539 | 0x3c13eb89, 2540 | 0x27a9ceee, 2541 | 0xc961b735, 2542 | 0xe51ce1ed, 2543 | 0xb1477a3c, 2544 | 0xdfd29c59, 2545 | 0x73f2553f, 2546 | 0xce141879, 2547 | 0x37c773bf, 2548 | 0xcdf753ea, 2549 | 0xaafd5f5b, 2550 | 0x6f3ddf14, 2551 | 0xdb447886, 2552 | 0xf3afca81, 2553 | 0xc468b93e, 2554 | 0x3424382c, 2555 | 0x40a3c25f, 2556 | 0xc31d1672, 2557 | 0x25e2bc0c, 2558 | 0x493c288b, 2559 | 0x950dff41, 2560 | 0x01a83971, 2561 | 0xb30c08de, 2562 | 0xe4b4d89c, 2563 | 0xc1566490, 2564 | 0x84cb7b61, 2565 | 0xb632d570, 2566 | 0x5c6c4874, 2567 | 0x57b8d042 2568 | ]; 2569 | 2570 | final _Tinv2 = [ 2571 | 0xf45150a7, 2572 | 0x417e5365, 2573 | 0x171ac3a4, 2574 | 0x273a965e, 2575 | 0xab3bcb6b, 2576 | 0x9d1ff145, 2577 | 0xfaacab58, 2578 | 0xe34b9303, 2579 | 0x302055fa, 2580 | 0x76adf66d, 2581 | 0xcc889176, 2582 | 0x02f5254c, 2583 | 0xe54ffcd7, 2584 | 0x2ac5d7cb, 2585 | 0x35268044, 2586 | 0x62b58fa3, 2587 | 0xb1de495a, 2588 | 0xba25671b, 2589 | 0xea45980e, 2590 | 0xfe5de1c0, 2591 | 0x2fc30275, 2592 | 0x4c8112f0, 2593 | 0x468da397, 2594 | 0xd36bc6f9, 2595 | 0x8f03e75f, 2596 | 0x9215959c, 2597 | 0x6dbfeb7a, 2598 | 0x5295da59, 2599 | 0xbed42d83, 2600 | 0x7458d321, 2601 | 0xe0492969, 2602 | 0xc98e44c8, 2603 | 0xc2756a89, 2604 | 0x8ef47879, 2605 | 0x58996b3e, 2606 | 0xb927dd71, 2607 | 0xe1beb64f, 2608 | 0x88f017ad, 2609 | 0x20c966ac, 2610 | 0xce7db43a, 2611 | 0xdf63184a, 2612 | 0x1ae58231, 2613 | 0x51976033, 2614 | 0x5362457f, 2615 | 0x64b1e077, 2616 | 0x6bbb84ae, 2617 | 0x81fe1ca0, 2618 | 0x08f9942b, 2619 | 0x48705868, 2620 | 0x458f19fd, 2621 | 0xde94876c, 2622 | 0x7b52b7f8, 2623 | 0x73ab23d3, 2624 | 0x4b72e202, 2625 | 0x1fe3578f, 2626 | 0x55662aab, 2627 | 0xebb20728, 2628 | 0xb52f03c2, 2629 | 0xc5869a7b, 2630 | 0x37d3a508, 2631 | 0x2830f287, 2632 | 0xbf23b2a5, 2633 | 0x0302ba6a, 2634 | 0x16ed5c82, 2635 | 0xcf8a2b1c, 2636 | 0x79a792b4, 2637 | 0x07f3f0f2, 2638 | 0x694ea1e2, 2639 | 0xda65cdf4, 2640 | 0x0506d5be, 2641 | 0x34d11f62, 2642 | 0xa6c48afe, 2643 | 0x2e349d53, 2644 | 0xf3a2a055, 2645 | 0x8a0532e1, 2646 | 0xf6a475eb, 2647 | 0x830b39ec, 2648 | 0x6040aaef, 2649 | 0x715e069f, 2650 | 0x6ebd5110, 2651 | 0x213ef98a, 2652 | 0xdd963d06, 2653 | 0x3eddae05, 2654 | 0xe64d46bd, 2655 | 0x5491b58d, 2656 | 0xc471055d, 2657 | 0x06046fd4, 2658 | 0x5060ff15, 2659 | 0x981924fb, 2660 | 0xbdd697e9, 2661 | 0x4089cc43, 2662 | 0xd967779e, 2663 | 0xe8b0bd42, 2664 | 0x8907888b, 2665 | 0x19e7385b, 2666 | 0xc879dbee, 2667 | 0x7ca1470a, 2668 | 0x427ce90f, 2669 | 0x84f8c91e, 2670 | 0x00000000, 2671 | 0x80098386, 2672 | 0x2b3248ed, 2673 | 0x111eac70, 2674 | 0x5a6c4e72, 2675 | 0x0efdfbff, 2676 | 0x850f5638, 2677 | 0xae3d1ed5, 2678 | 0x2d362739, 2679 | 0x0f0a64d9, 2680 | 0x5c6821a6, 2681 | 0x5b9bd154, 2682 | 0x36243a2e, 2683 | 0x0a0cb167, 2684 | 0x57930fe7, 2685 | 0xeeb4d296, 2686 | 0x9b1b9e91, 2687 | 0xc0804fc5, 2688 | 0xdc61a220, 2689 | 0x775a694b, 2690 | 0x121c161a, 2691 | 0x93e20aba, 2692 | 0xa0c0e52a, 2693 | 0x223c43e0, 2694 | 0x1b121d17, 2695 | 0x090e0b0d, 2696 | 0x8bf2adc7, 2697 | 0xb62db9a8, 2698 | 0x1e14c8a9, 2699 | 0xf1578519, 2700 | 0x75af4c07, 2701 | 0x99eebbdd, 2702 | 0x7fa3fd60, 2703 | 0x01f79f26, 2704 | 0x725cbcf5, 2705 | 0x6644c53b, 2706 | 0xfb5b347e, 2707 | 0x438b7629, 2708 | 0x23cbdcc6, 2709 | 0xedb668fc, 2710 | 0xe4b863f1, 2711 | 0x31d7cadc, 2712 | 0x63421085, 2713 | 0x97134022, 2714 | 0xc6842011, 2715 | 0x4a857d24, 2716 | 0xbbd2f83d, 2717 | 0xf9ae1132, 2718 | 0x29c76da1, 2719 | 0x9e1d4b2f, 2720 | 0xb2dcf330, 2721 | 0x860dec52, 2722 | 0xc177d0e3, 2723 | 0xb32b6c16, 2724 | 0x70a999b9, 2725 | 0x9411fa48, 2726 | 0xe9472264, 2727 | 0xfca8c48c, 2728 | 0xf0a01a3f, 2729 | 0x7d56d82c, 2730 | 0x3322ef90, 2731 | 0x4987c74e, 2732 | 0x38d9c1d1, 2733 | 0xca8cfea2, 2734 | 0xd498360b, 2735 | 0xf5a6cf81, 2736 | 0x7aa528de, 2737 | 0xb7da268e, 2738 | 0xad3fa4bf, 2739 | 0x3a2ce49d, 2740 | 0x78500d92, 2741 | 0x5f6a9bcc, 2742 | 0x7e546246, 2743 | 0x8df6c213, 2744 | 0xd890e8b8, 2745 | 0x392e5ef7, 2746 | 0xc382f5af, 2747 | 0x5d9fbe80, 2748 | 0xd0697c93, 2749 | 0xd56fa92d, 2750 | 0x25cfb312, 2751 | 0xacc83b99, 2752 | 0x1810a77d, 2753 | 0x9ce86e63, 2754 | 0x3bdb7bbb, 2755 | 0x26cd0978, 2756 | 0x596ef418, 2757 | 0x9aec01b7, 2758 | 0x4f83a89a, 2759 | 0x95e6656e, 2760 | 0xffaa7ee6, 2761 | 0xbc2108cf, 2762 | 0x15efe6e8, 2763 | 0xe7bad99b, 2764 | 0x6f4ace36, 2765 | 0x9fead409, 2766 | 0xb029d67c, 2767 | 0xa431afb2, 2768 | 0x3f2a3123, 2769 | 0xa5c63094, 2770 | 0xa235c066, 2771 | 0x4e7437bc, 2772 | 0x82fca6ca, 2773 | 0x90e0b0d0, 2774 | 0xa73315d8, 2775 | 0x04f14a98, 2776 | 0xec41f7da, 2777 | 0xcd7f0e50, 2778 | 0x91172ff6, 2779 | 0x4d768dd6, 2780 | 0xef434db0, 2781 | 0xaacc544d, 2782 | 0x96e4df04, 2783 | 0xd19ee3b5, 2784 | 0x6a4c1b88, 2785 | 0x2cc1b81f, 2786 | 0x65467f51, 2787 | 0x5e9d04ea, 2788 | 0x8c015d35, 2789 | 0x87fa7374, 2790 | 0x0bfb2e41, 2791 | 0x67b35a1d, 2792 | 0xdb9252d2, 2793 | 0x10e93356, 2794 | 0xd66d1347, 2795 | 0xd79a8c61, 2796 | 0xa1377a0c, 2797 | 0xf8598e14, 2798 | 0x13eb893c, 2799 | 0xa9ceee27, 2800 | 0x61b735c9, 2801 | 0x1ce1ede5, 2802 | 0x477a3cb1, 2803 | 0xd29c59df, 2804 | 0xf2553f73, 2805 | 0x141879ce, 2806 | 0xc773bf37, 2807 | 0xf753eacd, 2808 | 0xfd5f5baa, 2809 | 0x3ddf146f, 2810 | 0x447886db, 2811 | 0xafca81f3, 2812 | 0x68b93ec4, 2813 | 0x24382c34, 2814 | 0xa3c25f40, 2815 | 0x1d1672c3, 2816 | 0xe2bc0c25, 2817 | 0x3c288b49, 2818 | 0x0dff4195, 2819 | 0xa8397101, 2820 | 0x0c08deb3, 2821 | 0xb4d89ce4, 2822 | 0x566490c1, 2823 | 0xcb7b6184, 2824 | 0x32d570b6, 2825 | 0x6c48745c, 2826 | 0xb8d04257 2827 | ]; 2828 | 2829 | final _Tinv3 = [ 2830 | 0x5150a7f4, 2831 | 0x7e536541, 2832 | 0x1ac3a417, 2833 | 0x3a965e27, 2834 | 0x3bcb6bab, 2835 | 0x1ff1459d, 2836 | 0xacab58fa, 2837 | 0x4b9303e3, 2838 | 0x2055fa30, 2839 | 0xadf66d76, 2840 | 0x889176cc, 2841 | 0xf5254c02, 2842 | 0x4ffcd7e5, 2843 | 0xc5d7cb2a, 2844 | 0x26804435, 2845 | 0xb58fa362, 2846 | 0xde495ab1, 2847 | 0x25671bba, 2848 | 0x45980eea, 2849 | 0x5de1c0fe, 2850 | 0xc302752f, 2851 | 0x8112f04c, 2852 | 0x8da39746, 2853 | 0x6bc6f9d3, 2854 | 0x03e75f8f, 2855 | 0x15959c92, 2856 | 0xbfeb7a6d, 2857 | 0x95da5952, 2858 | 0xd42d83be, 2859 | 0x58d32174, 2860 | 0x492969e0, 2861 | 0x8e44c8c9, 2862 | 0x756a89c2, 2863 | 0xf478798e, 2864 | 0x996b3e58, 2865 | 0x27dd71b9, 2866 | 0xbeb64fe1, 2867 | 0xf017ad88, 2868 | 0xc966ac20, 2869 | 0x7db43ace, 2870 | 0x63184adf, 2871 | 0xe582311a, 2872 | 0x97603351, 2873 | 0x62457f53, 2874 | 0xb1e07764, 2875 | 0xbb84ae6b, 2876 | 0xfe1ca081, 2877 | 0xf9942b08, 2878 | 0x70586848, 2879 | 0x8f19fd45, 2880 | 0x94876cde, 2881 | 0x52b7f87b, 2882 | 0xab23d373, 2883 | 0x72e2024b, 2884 | 0xe3578f1f, 2885 | 0x662aab55, 2886 | 0xb20728eb, 2887 | 0x2f03c2b5, 2888 | 0x869a7bc5, 2889 | 0xd3a50837, 2890 | 0x30f28728, 2891 | 0x23b2a5bf, 2892 | 0x02ba6a03, 2893 | 0xed5c8216, 2894 | 0x8a2b1ccf, 2895 | 0xa792b479, 2896 | 0xf3f0f207, 2897 | 0x4ea1e269, 2898 | 0x65cdf4da, 2899 | 0x06d5be05, 2900 | 0xd11f6234, 2901 | 0xc48afea6, 2902 | 0x349d532e, 2903 | 0xa2a055f3, 2904 | 0x0532e18a, 2905 | 0xa475ebf6, 2906 | 0x0b39ec83, 2907 | 0x40aaef60, 2908 | 0x5e069f71, 2909 | 0xbd51106e, 2910 | 0x3ef98a21, 2911 | 0x963d06dd, 2912 | 0xddae053e, 2913 | 0x4d46bde6, 2914 | 0x91b58d54, 2915 | 0x71055dc4, 2916 | 0x046fd406, 2917 | 0x60ff1550, 2918 | 0x1924fb98, 2919 | 0xd697e9bd, 2920 | 0x89cc4340, 2921 | 0x67779ed9, 2922 | 0xb0bd42e8, 2923 | 0x07888b89, 2924 | 0xe7385b19, 2925 | 0x79dbeec8, 2926 | 0xa1470a7c, 2927 | 0x7ce90f42, 2928 | 0xf8c91e84, 2929 | 0x00000000, 2930 | 0x09838680, 2931 | 0x3248ed2b, 2932 | 0x1eac7011, 2933 | 0x6c4e725a, 2934 | 0xfdfbff0e, 2935 | 0x0f563885, 2936 | 0x3d1ed5ae, 2937 | 0x3627392d, 2938 | 0x0a64d90f, 2939 | 0x6821a65c, 2940 | 0x9bd1545b, 2941 | 0x243a2e36, 2942 | 0x0cb1670a, 2943 | 0x930fe757, 2944 | 0xb4d296ee, 2945 | 0x1b9e919b, 2946 | 0x804fc5c0, 2947 | 0x61a220dc, 2948 | 0x5a694b77, 2949 | 0x1c161a12, 2950 | 0xe20aba93, 2951 | 0xc0e52aa0, 2952 | 0x3c43e022, 2953 | 0x121d171b, 2954 | 0x0e0b0d09, 2955 | 0xf2adc78b, 2956 | 0x2db9a8b6, 2957 | 0x14c8a91e, 2958 | 0x578519f1, 2959 | 0xaf4c0775, 2960 | 0xeebbdd99, 2961 | 0xa3fd607f, 2962 | 0xf79f2601, 2963 | 0x5cbcf572, 2964 | 0x44c53b66, 2965 | 0x5b347efb, 2966 | 0x8b762943, 2967 | 0xcbdcc623, 2968 | 0xb668fced, 2969 | 0xb863f1e4, 2970 | 0xd7cadc31, 2971 | 0x42108563, 2972 | 0x13402297, 2973 | 0x842011c6, 2974 | 0x857d244a, 2975 | 0xd2f83dbb, 2976 | 0xae1132f9, 2977 | 0xc76da129, 2978 | 0x1d4b2f9e, 2979 | 0xdcf330b2, 2980 | 0x0dec5286, 2981 | 0x77d0e3c1, 2982 | 0x2b6c16b3, 2983 | 0xa999b970, 2984 | 0x11fa4894, 2985 | 0x472264e9, 2986 | 0xa8c48cfc, 2987 | 0xa01a3ff0, 2988 | 0x56d82c7d, 2989 | 0x22ef9033, 2990 | 0x87c74e49, 2991 | 0xd9c1d138, 2992 | 0x8cfea2ca, 2993 | 0x98360bd4, 2994 | 0xa6cf81f5, 2995 | 0xa528de7a, 2996 | 0xda268eb7, 2997 | 0x3fa4bfad, 2998 | 0x2ce49d3a, 2999 | 0x500d9278, 3000 | 0x6a9bcc5f, 3001 | 0x5462467e, 3002 | 0xf6c2138d, 3003 | 0x90e8b8d8, 3004 | 0x2e5ef739, 3005 | 0x82f5afc3, 3006 | 0x9fbe805d, 3007 | 0x697c93d0, 3008 | 0x6fa92dd5, 3009 | 0xcfb31225, 3010 | 0xc83b99ac, 3011 | 0x10a77d18, 3012 | 0xe86e639c, 3013 | 0xdb7bbb3b, 3014 | 0xcd097826, 3015 | 0x6ef41859, 3016 | 0xec01b79a, 3017 | 0x83a89a4f, 3018 | 0xe6656e95, 3019 | 0xaa7ee6ff, 3020 | 0x2108cfbc, 3021 | 0xefe6e815, 3022 | 0xbad99be7, 3023 | 0x4ace366f, 3024 | 0xead4099f, 3025 | 0x29d67cb0, 3026 | 0x31afb2a4, 3027 | 0x2a31233f, 3028 | 0xc63094a5, 3029 | 0x35c066a2, 3030 | 0x7437bc4e, 3031 | 0xfca6ca82, 3032 | 0xe0b0d090, 3033 | 0x3315d8a7, 3034 | 0xf14a9804, 3035 | 0x41f7daec, 3036 | 0x7f0e50cd, 3037 | 0x172ff691, 3038 | 0x768dd64d, 3039 | 0x434db0ef, 3040 | 0xcc544daa, 3041 | 0xe4df0496, 3042 | 0x9ee3b5d1, 3043 | 0x4c1b886a, 3044 | 0xc1b81f2c, 3045 | 0x467f5165, 3046 | 0x9d04ea5e, 3047 | 0x015d358c, 3048 | 0xfa737487, 3049 | 0xfb2e410b, 3050 | 0xb35a1d67, 3051 | 0x9252d2db, 3052 | 0xe9335610, 3053 | 0x6d1347d6, 3054 | 0x9a8c61d7, 3055 | 0x377a0ca1, 3056 | 0x598e14f8, 3057 | 0xeb893c13, 3058 | 0xceee27a9, 3059 | 0xb735c961, 3060 | 0xe1ede51c, 3061 | 0x7a3cb147, 3062 | 0x9c59dfd2, 3063 | 0x553f73f2, 3064 | 0x1879ce14, 3065 | 0x73bf37c7, 3066 | 0x53eacdf7, 3067 | 0x5f5baafd, 3068 | 0xdf146f3d, 3069 | 0x7886db44, 3070 | 0xca81f3af, 3071 | 0xb93ec468, 3072 | 0x382c3424, 3073 | 0xc25f40a3, 3074 | 0x1672c31d, 3075 | 0xbc0c25e2, 3076 | 0x288b493c, 3077 | 0xff41950d, 3078 | 0x397101a8, 3079 | 0x08deb30c, 3080 | 0xd89ce4b4, 3081 | 0x6490c156, 3082 | 0x7b6184cb, 3083 | 0xd570b632, 3084 | 0x48745c6c, 3085 | 0xd04257b8 3086 | ]; 3087 | --------------------------------------------------------------------------------