Skip to content

Commit ea8ea7f

Browse files
committed
Added docs
1 parent 0017020 commit ea8ea7f

File tree

3 files changed

+136
-27
lines changed

3 files changed

+136
-27
lines changed

README.md

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,82 @@
1-
<!--
2-
This README describes the package. If you publish this package to pub.dev,
3-
this README's contents appear on the landing page for your package.
1+
> Minimum Dart SDK 3.10 (Flutter 3.38) with Native Assets/hooks support.
42
5-
For information about how to write a good package README, see the guide for
6-
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
3+
This package builds OpenSSL from source and exposes its full C surface directly to Dart via FFI. There are no Dart-side abstractions: call the OpenSSL APIs as you would in C, manage memory manually, and follow the official OpenSSL documentation for usage and lifetime rules.
74

8-
For general information about developing packages, see the Dart guide for
9-
[creating packages](https://dart.dev/guides/libraries/create-packages)
10-
and the Flutter guide for
11-
[developing packages and plugins](https://flutter.dev/to/develop-packages).
12-
-->
5+
## What you get
136

14-
TODO: Put a short description of the package here that helps potential users
15-
know whether this package might be useful for them.
16-
17-
## Features
18-
19-
TODO: List what your package can do. Maybe include images, gifs, or videos.
7+
- Full OpenSSL C API available in Dart (headers mirrored into FFI bindings).
8+
- Native assets build step that compiles OpenSSL locally the first time you run the app.
9+
- No opinionated wrappers; you stay in control of allocation and cleanup.
2010

2111
## Getting started
2212

23-
TODO: List prerequisites and provide or point to information on how to
24-
start using the package.
13+
1) Add the package: `dart pub add openssl` (or add it to your `pubspec.yaml`).
14+
2) Run your app once to trigger the native build (about 1 minute on first run).
2515

26-
## Usage
16+
## Using the bindings
2717

28-
TODO: Include short and useful examples for package users. Add longer examples
29-
to `/example` folder.
18+
Import and call OpenSSL functions directly; the generated bindings live under `lib/src/third_party/openssl.g.dart`.
3019

3120
```dart
32-
const like = 'sample';
21+
import 'dart:convert';
22+
import 'dart:typed_data';
23+
import 'package:ffi/ffi.dart';
24+
import 'package:openssl/openssl.dart' as openssl;
25+
26+
Uint8List aes(Uint8List input, Uint8List key, Uint8List iv, {required bool encrypt}) {
27+
return using((arena) {
28+
final ctx = openssl.EVP_CIPHER_CTX_new();
29+
final inPtr = arena.allocate<Uint8>(input.isEmpty ? 1 : input.length);
30+
final keyPtr = arena.allocate<Uint8>(key.length);
31+
final ivPtr = arena.allocate<Uint8>(iv.length);
32+
final outPtr = arena.allocate<Uint8>(input.length + openssl.EVP_MAX_BLOCK_LENGTH);
33+
final outLenPtr = arena.allocate<Int>(2);
34+
35+
inPtr.asTypedList(input.length).setAll(0, input);
36+
keyPtr.asTypedList(key.length).setAll(0, key);
37+
ivPtr.asTypedList(iv.length).setAll(0, iv);
38+
39+
final initResult = encrypt
40+
? openssl.EVP_EncryptInit_ex(ctx, openssl.EVP_aes_256_cbc(), nullptr, keyPtr.cast(), ivPtr.cast())
41+
: openssl.EVP_DecryptInit_ex(ctx, openssl.EVP_aes_256_cbc(), nullptr, keyPtr.cast(), ivPtr.cast());
42+
if (initResult != 1) throw StateError('init failed');
43+
44+
final updateResult = encrypt
45+
? openssl.EVP_EncryptUpdate(ctx, outPtr.cast(), outLenPtr, inPtr.cast(), input.length)
46+
: openssl.EVP_DecryptUpdate(ctx, outPtr.cast(), outLenPtr, inPtr.cast(), input.length);
47+
if (updateResult != 1) throw StateError('update failed');
48+
49+
var outLen = outLenPtr.value;
50+
final finalResult = encrypt
51+
? openssl.EVP_EncryptFinal_ex(ctx, outPtr.elementAt(outLen).cast(), outLenPtr)
52+
: openssl.EVP_DecryptFinal_ex(ctx, outPtr.elementAt(outLen).cast(), outLenPtr);
53+
if (finalResult != 1) throw StateError('final failed');
54+
55+
outLen += outLenPtr.value;
56+
return Uint8List.fromList(outPtr.asTypedList(outLen));
57+
});
58+
}
59+
60+
void main() {
61+
final key = utf8.encode('Nc92PMoPjcIls5QoXeki5yIPuhjjWMcx');
62+
final iv = utf8.encode('1234567890123456');
63+
final plaintext = utf8.encode('Secret message for AES-256-CBC');
64+
65+
final encrypted = aes(plaintext, Uint8List.fromList(key), Uint8List.fromList(iv), encrypt: true);
66+
final decrypted = aes(encrypted, Uint8List.fromList(key), Uint8List.fromList(iv), encrypt: false);
67+
68+
print('cipher (b64): ${base64.encode(encrypted)}');
69+
print('roundtrip: ${utf8.decode(decrypted)}');
70+
}
3371
```
3472

35-
## Additional information
73+
Remember: follow OpenSSL docs for allocation/free patterns (`OPENSSL_free`, `EVP_*` lifecycle, etc.).
74+
75+
## Build notes and roadmap
3676

37-
TODO: Tell users more about the package: where to find more information, how to
38-
contribute to the package, how to file issues, what response they can expect
39-
from the package authors, and more.
77+
- First build compiles OpenSSL; subsequent runs are faster. The goal is to ship precompiled binaries later to skip this step.
78+
- Native assets require Flutter 3.38+/Dart 3.10+ to run the hook pipeline.
4079

80+
## Contributing
4181

42-
`git submodule update --init`
82+
For local builds, regenerating bindings, and working with the OpenSSL submodule, see `contrib.md`.

contrib.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Contributing and local builds
2+
3+
- Tooling: Dart 3.10+ / Flutter 3.38+ with Native Assets; standard C build toolchain (perl + make/clang on macOS/Linux; MSVC + perl + jom on Windows—hook can download perl/jom if missing).
4+
- Clone with submodules: `git clone --recurse-submodules <repo>` (or `git submodule update --init` after cloning).
5+
- Install deps: `dart pub get`.
6+
- Regenerate bindings after updating headers: `dart run tool/ffigen.dart`.
7+
- Build the native assets: run the app (`dart run`) and the hook compiles OpenSSL (first build ~1 minute).
8+
- Tests: `dart test`.

example/main.dart

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import 'dart:convert';
2+
import 'dart:ffi';
3+
import 'dart:typed_data';
4+
5+
import 'package:ffi/ffi.dart';
6+
import 'package:openssl/openssl.dart' as openssl;
7+
8+
Uint8List aes(Uint8List input, Uint8List key, Uint8List iv, {required bool encrypt}) {
9+
if (key.length != 32) {
10+
throw ArgumentError.value(key.length, 'key', 'Key must be 32 bytes for AES-256-CBC');
11+
}
12+
if (iv.length != 16) {
13+
throw ArgumentError.value(iv.length, 'iv', 'IV must be 16 bytes for AES-256-CBC');
14+
}
15+
16+
return using((arena) {
17+
final ctx = openssl.EVP_CIPHER_CTX_new();
18+
if (ctx == nullptr) throw StateError('Failed to create EVP_CIPHER_CTX');
19+
20+
final inPtr = arena.allocate<Uint8>(input.isEmpty ? 1 : input.length);
21+
final keyPtr = arena.allocate<Uint8>(key.length);
22+
final ivPtr = arena.allocate<Uint8>(iv.length);
23+
final outPtr = arena.allocate<Uint8>(input.length + openssl.EVP_MAX_BLOCK_LENGTH);
24+
final outLenPtr = arena.allocate<Int>(2);
25+
26+
inPtr.asTypedList(input.length).setAll(0, input);
27+
keyPtr.asTypedList(key.length).setAll(0, key);
28+
ivPtr.asTypedList(iv.length).setAll(0, iv);
29+
30+
final initResult = encrypt
31+
? openssl.EVP_EncryptInit_ex(ctx, openssl.EVP_aes_256_cbc(), nullptr, keyPtr.cast(), ivPtr.cast())
32+
: openssl.EVP_DecryptInit_ex(ctx, openssl.EVP_aes_256_cbc(), nullptr, keyPtr.cast(), ivPtr.cast());
33+
if (initResult != 1) throw StateError('OpenSSL AES init step failed: $initResult');
34+
35+
final updateResult = encrypt
36+
? openssl.EVP_EncryptUpdate(ctx, outPtr.cast(), outLenPtr, inPtr.cast(), input.length)
37+
: openssl.EVP_DecryptUpdate(ctx, outPtr.cast(), outLenPtr, inPtr.cast(), input.length);
38+
if (updateResult != 1) throw StateError('OpenSSL AES update step failed: $updateResult');
39+
40+
var outLen = outLenPtr.value;
41+
final finalResult = encrypt
42+
? openssl.EVP_EncryptFinal_ex(ctx, outPtr.elementAt(outLen).cast(), outLenPtr)
43+
: openssl.EVP_DecryptFinal_ex(ctx, outPtr.elementAt(outLen).cast(), outLenPtr);
44+
if (finalResult != 1) throw StateError('OpenSSL AES final step failed: $finalResult');
45+
46+
outLen += outLenPtr.value;
47+
return Uint8List.fromList(outPtr.asTypedList(outLen));
48+
});
49+
}
50+
51+
void main() {
52+
final key = utf8.encode('Nc92PMoPjcIls5QoXeki5yIPuhjjWMcx');
53+
final iv = utf8.encode('1234567890123456');
54+
final plaintext = utf8.encode('Secret message for AES-256-CBC');
55+
56+
final encrypted = aes(Uint8List.fromList(plaintext), Uint8List.fromList(key), Uint8List.fromList(iv), encrypt: true);
57+
final decrypted = aes(encrypted, Uint8List.fromList(key), Uint8List.fromList(iv), encrypt: false);
58+
59+
print('cipher (base64): ${base64.encode(encrypted)}');
60+
print('roundtrip text: ${utf8.decode(decrypted)}');
61+
}

0 commit comments

Comments
 (0)