blob: 2cbeb1ad4fd1e31623df28e97e4e1207b31ebe41 [file] [log] [blame]
/// Demonstrates different approaches to importing Pointy Castle libraries.
///
/// - import-demo-1.dart - import 'package:pointycastle/pointycastle.dart';
/// can only used registry
/// - import-demo-2.dart - import 'package:pointycastle/export.dart';
/// can use registry and all constructors
/// - import-demo-3.dart - import 'package:pointycastle/api.dart' plus
/// individual libraries; can use registry and
/// constructors from individually imported libraries
/// - import-demo-4.dart - import 'package:pointycastle/api.dart' plus
/// individual libraries; same as 3, but tries
/// to use the registry for classes that have NOT
/// been individually imported. This should not
/// work, but strangely does.
///
/// The useRegistry and explicit functions are the same in all examples,
/// but they can or cannot be used depending on what imports were used.
///
/// To see the differences between the examples, run 'diff' on the files.
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:pointycastle/pointycastle.dart';
import 'package:pointycastle/src/platform_check/platform_check.dart';
void main() {
useRegistry();
// useConstructors(); // cannot use: can only use the registry
}
void useRegistry() {
final sha256 = Digest('SHA-256');
final sha1 = Digest('SHA-1');
final md5 = Digest('MD5');
final _digest = sha256.process(Uint8List.fromList(_data));
final hmacSha256 = Mac('SHA-256/HMAC');
final hmacSha512 = Mac('SHA-512/HMAC');
final hmacMd5 = Mac('MD5/HMAC');
final _hmacValue = hmacSha256.process(Uint8List.fromList(_data));
//final kd = KeyDerivator('SHA-256/HMAC/PBKDF2');
final _sGen = Random.secure();
final _seed = Platform.instance.platformEntropySource().getBytes(32);
final secRnd = SecureRandom('Fortuna')..seed(KeyParameter(_seed));
// AES-CBC encryption
final _salt = secRnd.nextBytes(32);
final keyDerivator256 = KeyDerivator('SHA-256/HMAC/PBKDF2')
..init(Pbkdf2Parameters(_salt, 10000, 256 ~/ 8));
final aes256key = keyDerivator256.process(Uint8List.fromList(_secret));
final _iv = secRnd.nextBytes(128 ~/ 8);
final aesCbc = BlockCipher('AES/CBC')
..init(true, ParametersWithIV(KeyParameter(aes256key), _iv));
final _paddedData = Uint8List(
_data.length + (aesCbc.blockSize - (_data.length % aesCbc.blockSize)))
..setAll(0, _data);
Padding('PKCS7').addPadding(_paddedData, _data.length);
final _ciphertext = aesCbc.process(_paddedData);
// RSA key generation and signing
final keyGen = KeyGenerator('RSA');
keyGen.init(ParametersWithRandom(
RSAKeyGeneratorParameters(BigInt.parse('65537'), 2048, 64), secRnd));
final _pair = keyGen.generateKeyPair();
final signer = Signer('SHA-256/RSA')
..init(true, PrivateKeyParameter<RSAPrivateKey>(_pair.privateKey));
final _signature =
signer.generateSignature(Uint8List.fromList(_data)) as RSASignature;
final verifier = Signer('SHA-256/RSA')
..init(false, PublicKeyParameter<RSAPublicKey>(_pair.publicKey));
final sigOk = verifier.verifySignature(Uint8List.fromList(_data), _signature);
print('''
Data: '${utf8.decode(_data)}'
SHA-256: ${bin2hex(_digest)}
SHA-1: ${bin2hex(sha1.process(Uint8List.fromList(_data)))}
MD5: ${bin2hex(md5.process(Uint8List.fromList(_data)), separator: ':')}
HMAC-SHA256: ${bin2hex(_hmacValue)}
HMAC-512: ${bin2hex(hmacSha512.process(Uint8List.fromList(_data)))}
HMAC-MD5: ${bin2hex(hmacMd5.process(Uint8List.fromList(_data)))}
AES-CBC ciphertext:
${bin2hex(_ciphertext, wrap: 64)}
Signature:
${bin2hex(_signature.bytes, wrap: 64)}
Verifies: $sigOk
''');
}
/* BEGIN: useConstructors commented out
void useConstructors() {
// Digest
final sha256 = SHA256Digest();
final sha1 = SHA1Digest();
final md5 = MD5Digest();
final _digest = sha256.process(_data);
// HMAC
final hmacSha256 = HMac(SHA256Digest(), 64)..init(KeyParameter(_secret));
final hmacSha512 = HMac(SHA512Digest(), 128)..init(KeyParameter(_secret));
final hmacMd5 = HMac(MD5Digest(), 64)..init(KeyParameter(_secret));
final _hmacValue = hmacSha256.process(_data);
// Secure random number generator
final _sGen = Random.secure();
final _seed =
_KeyParameter(Platform.instance.platformEntropySource().getBytes(32);
final secRnd = FortunaRandom()..seed(KeyParameter(_seed));
// AES-CBC encryption
final _salt = secRnd.nextBytes(32);
final keyDerivator256 = PBKDF2KeyDerivator(HMac(SHA256Digest(), 64))
..init(Pbkdf2Parameters(_salt, 10000, 256 ~/ 8));
final aes256key = keyDerivator256.process(_secret);
final _iv = secRnd.nextBytes(128 ~/ 8);
final aesCbc = CBCBlockCipher(AESFastEngine())
..init(true, ParametersWithIV(KeyParameter(aes256key), _iv));
final _paddedData = Uint8List(
_data.length + (aesCbc.blockSize - (_data.length % aesCbc.blockSize)))
..setAll(0, _data);
PKCS7Padding().addPadding(_paddedData, _data.length);
final _ciphertext = aesCbc.process(_paddedData);
// RSA key generation and signing
final keyGen = RSAKeyGenerator();
keyGen.init(ParametersWithRandom(
RSAKeyGeneratorParameters(BigInt.parse('65537'), 2048, 64), secRnd));
final _pair = keyGen.generateKeyPair();
final signer = RSASigner(SHA256Digest(), '0609608648016503040201')
..init(true, PrivateKeyParameter<RSAPrivateKey>(_pair.privateKey));
final _signature = signer.generateSignature(_data);
final verifier = RSASigner(SHA256Digest(), '0609608648016503040201')
..init(false, PublicKeyParameter<RSAPublicKey>(_pair.publicKey));
final sigOk = verifier.verifySignature(_data, _signature);
print('''
Data: '${utf8.decode(_data)}'
SHA-256: ${bin2hex(_digest)}
SHA-1: ${bin2hex(sha1.process(_data))}
MD5: ${bin2hex(md5.process(_data), separator: ':')}
HMAC-SHA256: ${bin2hex(_hmacValue)}
HMAC-512: ${bin2hex(hmacSha512.process(_data))}
HMAC-MD5: ${bin2hex(hmacMd5.process(_data))}
AES-CBC ciphertext:
${bin2hex(_ciphertext, wrap: 64)}
Signature:
${bin2hex(_signature.bytes, wrap: 64)}
Verifies: $sigOk
''');
}
END: useConstructors commented out */
//----------------------------------------------------------------
final _data = utf8.encode('Hello world!');
final _secret = utf8.encode('p@ssw0rd');
//----------------------------------------------------------------
/// Represent bytes in hexadecimal
///
/// If a [separator] is provided, it is placed the hexadecimal characters
/// representing each byte. Otherwise, all the hexadecimal characters are
/// simply concatenated together.
String bin2hex(Uint8List bytes, {String? separator, int? wrap}) {
var len = 0;
final buf = StringBuffer();
for (final b in bytes) {
final s = b.toRadixString(16);
if (buf.isNotEmpty && separator != null) {
buf.write(separator);
len += separator.length;
}
if (wrap != null && wrap < len + 2) {
buf.write('\n');
len = 0;
}
buf.write('${(s.length == 1) ? '0' : ''}$s');
len += 2;
}
return buf.toString();
}