-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from tekartik/dart3a
Dart3a
- Loading branch information
Showing
10 changed files
with
287 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,10 @@ | ||
export 'package:tekartik_app_crypto/src/encrypt.dart' | ||
show encrypt, decrypt, StringEncrypter, defaultEncryptedFromRawPassword; | ||
|
||
export 'src/aes.dart' | ||
show | ||
aesEncrypterFromPassword, | ||
encryptTextPassword16FromText, | ||
aesDecrypt, | ||
aesEncrypt; | ||
export 'src/salsa20.dart' show salsa20EncrypterFromPassword; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:crypto/crypto.dart'; | ||
import 'package:encrypt/encrypt.dart'; | ||
|
||
import 'encrypt.dart'; | ||
|
||
/// Simple md5 hash | ||
String encryptTextPassword16FromText(String password) { | ||
return base64Encode(md5.convert(utf8.encode(password)).bytes) | ||
.substring(0, 16); | ||
} | ||
|
||
/// aes encrypted using any password (use MD5), random data prepended | ||
StringEncrypter aesEncrypterFromPassword(String password) { | ||
return _AesStringEncrypter(_aesEncrypterFromPassword(password)); | ||
} | ||
|
||
Encrypter _aesEncrypterFromPassword(String password) { | ||
final key = Key.fromUtf8(password); // _generateEncryptPassword(password)); | ||
return Encrypter(AES(key)); | ||
} | ||
|
||
class _AesStringEncrypter implements StringEncrypter { | ||
final Encrypter encrypter; | ||
|
||
_AesStringEncrypter(this.encrypter); | ||
@override | ||
String decrypt(String encrypted) { | ||
// Read the initial value that was prepended | ||
assert(encrypted.length >= 24); | ||
final iv = base64.decode(encrypted.substring(0, 24)); | ||
|
||
// Extract the real input | ||
encrypted = encrypted.substring(24); | ||
|
||
// Decode the input | ||
var decoded = encrypter.decrypt64(encrypted, iv: IV(iv)); | ||
return decoded; | ||
} | ||
|
||
IV _generateIv() { | ||
final iv = IV.fromSecureRandom(16); | ||
return iv; | ||
} | ||
|
||
@override | ||
String encrypt(String input) { | ||
final iv = _generateIv(); | ||
|
||
// Encode the input value | ||
final encoded = encrypter.encrypt(input, iv: iv).base64; | ||
|
||
var ivEncoded = iv.base64; | ||
assert(ivEncoded.length == 24); | ||
// Prepend the initial value | ||
return '$ivEncoded$encoded'; | ||
} | ||
} | ||
|
||
class AesWithIVEntrypter extends _AesStringEncrypter { | ||
final IV iv; | ||
|
||
/// Must be 16 bytes | ||
final String password; | ||
AesWithIVEntrypter(this.password, this.iv) | ||
: super(_aesEncrypterFromPassword(password)); | ||
@override | ||
IV _generateIv() { | ||
return iv; | ||
} | ||
} | ||
|
||
/// encrypt the [decoded] text using [password]. | ||
/// | ||
/// [password] must be ascii character of length 16, 24 or 32. | ||
/// | ||
/// returns a base 64 encrypted string. | ||
/// | ||
/// Encryption used is AES. | ||
String aesEncrypt(String decoded, String password) => | ||
aesEncrypterFromPassword(password).encrypt(decoded); | ||
|
||
/// decrypt the [encoded] text using [password]. | ||
/// | ||
/// [encoded] is base 64 string got from the encrypt method using the same | ||
/// [password] | ||
/// | ||
/// Encryption used is AES. | ||
String aesDecrypt(String encoded, String password) => | ||
aesEncrypterFromPassword(password).decrypt(encoded); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,98 @@ | ||
import 'package:encrypt/encrypt.dart'; | ||
import 'package:tekartik_app_crypto/encrypt.dart'; | ||
import 'package:tekartik_app_crypto/src/aes.dart'; | ||
import 'package:tekartik_app_crypto/src/generate_password.dart' | ||
show generatePassword; | ||
import 'package:test/test.dart'; | ||
|
||
String encrypt(String decoded, String password) { | ||
final key = Key.fromUtf8(password); | ||
final iv = IV.fromLength(16); | ||
final encrypter = Encrypter(AES(key)); | ||
return encrypter.encrypt(decoded, iv: iv).base64; | ||
} | ||
void main() { | ||
void aesRoundTrip(String decoded, String password) { | ||
var encrypter = aesEncrypterFromPassword(password); | ||
var encrypted = encrypter.encrypt(decoded); | ||
print('${decoded.length}:${encrypted.length}'); | ||
encrypter = aesEncrypterFromPassword(password); | ||
expect(encrypter.decrypt(encrypted), decoded); | ||
} | ||
|
||
String decrypt(String encoded, String password) { | ||
final key = Key.fromUtf8(password); | ||
final iv = IV.fromLength(16); | ||
final encrypter = Encrypter(AES(key)); | ||
return encrypter.decrypt(Encrypted.fromBase64(encoded), iv: iv); | ||
} | ||
test('aes encrypt decrypt', () { | ||
var password = r'E4x*$TwbkJC-xK4KGC4zJF9j*Rh&WLgR'; | ||
var encrypter = AesWithIVEntrypter(password, IV.allZerosOfLength(16)); | ||
|
||
void main() { | ||
test('AES encrypt/decrypt', () { | ||
expect(encrypt('test', password), 'amGhyRRLUIoE59IiEys5Vw=='); | ||
expect(encrypter.encrypt('test'), | ||
'AAAAAAAAAAAAAAAAAAAAAA==amGhyRRLUIoE59IiEys5Vw=='); | ||
expect( | ||
encrypter.decrypt('AAAAAAAAAAAAAAAAAAAAAA==amGhyRRLUIoE59IiEys5Vw=='), | ||
'test'); | ||
}); | ||
|
||
test('aes decrypt', () { | ||
var password = r'E4x*$TwbkJC-xK4KGC4zJF9j*Rh&WLgR'; | ||
expect(decrypt('amGhyRRLUIoE59IiEys5Vw==', password), 'test'); | ||
var encrypter = aesEncrypterFromPassword(password); | ||
|
||
expect( | ||
encrypter.encrypt('test'), | ||
isNot( | ||
'kEH3mkatSK4yiDu95hZj3Q==0aN1ouMw1HhKY6L8sibkgA==')); // - different each time | ||
expect( | ||
encrypter.decrypt('kEH3mkatSK4yiDu95hZj3Q==0aN1ouMw1HhKY6L8sibkgA=='), | ||
'test'); | ||
expect( | ||
aesDecrypt( | ||
'kEH3mkatSK4yiDu95hZj3Q==0aN1ouMw1HhKY6L8sibkgA==', password), | ||
'test'); | ||
expect(aesEncrypt('test', password), | ||
isNot('19/EiVx5ICKR/IpS05DYmA==rqLU4PjkNP8W/SiI1dVgAA==')); | ||
expect( | ||
aesDecrypt( | ||
'19/EiVx5ICKR/IpS05DYmA==rqLU4PjkNP8W/SiI1dVgAA==', password), | ||
'test'); | ||
expect(aesDecrypt(aesEncrypt('test', password), password), 'test'); | ||
}); | ||
test('aes', () { | ||
var aes = aesEncrypterFromPassword(encryptTextPassword16FromText('test')); | ||
var encrypted = aes.encrypt('test'); | ||
aes = aesEncrypterFromPassword(encryptTextPassword16FromText('test')); | ||
expect(aes.decrypt(encrypted), 'test'); | ||
|
||
String textWithLength(int length) { | ||
return List.generate(length, (i) => i.toString().substring(0, 1)).join(); | ||
} | ||
|
||
aesRoundTrip('test', encryptTextPassword16FromText('test')); | ||
//aesRoundTrip('', ''); | ||
aesRoundTrip('1', encryptTextPassword16FromText('2')); | ||
aesRoundTrip(textWithLength(4096), | ||
encryptTextPassword16FromText(textWithLength(4096))); | ||
// _salsa20RoundTrip(textWithLength(40960), textWithLength(40960)); | ||
aesRoundTrip(textWithLength(4096000), | ||
encryptTextPassword16FromText(textWithLength(4096000))); | ||
|
||
var password = generatePassword(); | ||
aes = aesEncrypterFromPassword(password); | ||
var sw = Stopwatch()..start(); | ||
var count = 1000; | ||
for (var i = 0; i < count; i++) { | ||
aes.decrypt(aes.encrypt(textWithLength(count * 10))); | ||
} | ||
print('aes round trip: ${sw.elapsedMilliseconds} ms'); | ||
sw = Stopwatch()..start(); | ||
|
||
for (var i = 0; i < count; i++) { | ||
aesDecrypt(aesEncrypt(textWithLength(count * 10), password), password); | ||
} | ||
print('aesDecrypt/aesEncrypt: ${sw.elapsedMilliseconds} ms'); | ||
|
||
var encrypteds = List.generate(count, (index) => ''); | ||
sw = Stopwatch()..start(); | ||
for (var i = 0; i < count; i++) { | ||
encrypteds[i] = aes.encrypt(textWithLength(count * 10)); | ||
} | ||
print('aes encrypt: ${sw.elapsedMilliseconds} ms'); | ||
sw = Stopwatch()..start(); | ||
for (var i = 0; i < count; i++) { | ||
aes.decrypt(encrypteds[i]); | ||
} | ||
print('aes decrypt: ${sw.elapsedMilliseconds} ms'); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import 'dart:typed_data'; | ||
|
||
import 'package:encrypt/encrypt.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
String aesEncrypt(String decoded, String password) { | ||
final key = Key.fromUtf8(password); | ||
// final iv = IV.fromLength(16); | ||
final iv = IV(Uint8List(16)); | ||
final encrypter = Encrypter(AES(key)); | ||
return encrypter.encrypt(decoded, iv: iv).base64; | ||
} | ||
|
||
String aesDecrypt(String encoded, String password) { | ||
final key = Key.fromUtf8(password); | ||
// final iv = IV.fromLength(16); | ||
final iv = IV(Uint8List(16)); | ||
final encrypter = Encrypter(AES(key)); | ||
return encrypter.decrypt(Encrypted.fromBase64(encoded), iv: iv); | ||
} | ||
|
||
void main() { | ||
test('AES encrypt/decrypt', () { | ||
var password = r'E4x*$TwbkJC-xK4KGC4zJF9j*Rh&WLgR'; | ||
expect(aesEncrypt('test', password), 'amGhyRRLUIoE59IiEys5Vw=='); | ||
expect(aesDecrypt('amGhyRRLUIoE59IiEys5Vw==', password), 'test'); | ||
}); | ||
} |
Oops, something went wrong.