-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d224401
commit 39d5ac7
Showing
20 changed files
with
1,388 additions
and
4 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
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
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,117 @@ | ||
import 'dart:typed_data'; | ||
|
||
import 'package:freezed_annotation/freezed_annotation.dart'; | ||
|
||
import 'helpers/validations.dart'; | ||
import 'key_pair.dart'; | ||
import 'secure_key.dart'; | ||
|
||
part 'kx.freezed.dart'; | ||
|
||
/// A pair of session keys that can be used for secure data transfer. | ||
/// | ||
/// This class simply holds a [rx]Key and a [tx]Key. The [rx] should be used to | ||
/// decrypt received data and [tx] to encrypt data before sending it. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange. | ||
@freezed | ||
class SessionKeys with _$SessionKeys { | ||
const SessionKeys._(); | ||
|
||
// ignore: sort_unnamed_constructors_first | ||
const factory SessionKeys({ | ||
/// Session key to be used to decrypt received data | ||
required SecureKey rx, | ||
|
||
/// Session key to be used to encrypt data before transmitting it | ||
required SecureKey tx, | ||
}) = _SessionKeys; | ||
|
||
/// Shortcut to dispose both contained keys. | ||
/// | ||
/// Simply calls [SecureKey.dispose] on [rx] and [tx] | ||
void dispose() { | ||
rx.dispose(); | ||
tx.dispose(); | ||
} | ||
} | ||
|
||
/// A meta class that provides access to all libsodium kx APIs. | ||
/// | ||
/// This class provides the dart interface for the crypto operations documented | ||
/// in https://libsodium.gitbook.io/doc/key_exchange. | ||
/// Please refer to that documentation for more details about these APIs. | ||
abstract class Kx { | ||
const Kx._(); // coverage:ignore-line | ||
|
||
/// Provides crypto_kx_PUBLICKEYBYTES. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#constants | ||
int get publicKeyBytes; | ||
|
||
/// Provides crypto_kx_SECRETKEYBYTES. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#constants | ||
int get secretKeyBytes; | ||
|
||
/// Provides crypto_kx_SEEDBYTES. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#constants | ||
int get seedBytes; | ||
|
||
/// Provides crypto_kx_SESSIONKEYBYTES. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#constants | ||
int get sessionKeyBytes; | ||
|
||
/// Provides crypto_kx_keypair. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#usage | ||
KeyPair keyPair(); | ||
|
||
/// Provides crypto_kx_seed_keypair. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#usage | ||
KeyPair seedKeyPair(SecureKey seed); | ||
|
||
/// Provides crypto_kx_client_session_keys. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#usage | ||
SessionKeys clientSessionKeys({ | ||
required Uint8List clientPublicKey, | ||
required SecureKey clientSecretKey, | ||
required Uint8List serverPublicKey, | ||
}); | ||
|
||
/// Provides crypto_kx_server_session_keys. | ||
/// | ||
/// See https://libsodium.gitbook.io/doc/key_exchange#usage | ||
SessionKeys serverSessionKeys({ | ||
required Uint8List serverPublicKey, | ||
required SecureKey serverSecretKey, | ||
required Uint8List clientPublicKey, | ||
}); | ||
} | ||
|
||
@internal | ||
mixin KxValidations implements Kx { | ||
void validatePublicKey(Uint8List publicKey, String namePrefix) => | ||
Validations.checkIsSame( | ||
publicKey.length, | ||
publicKeyBytes, | ||
'${namePrefix}PublicKey', | ||
); | ||
|
||
void validateSecretKey(SecureKey secretKey, String namePrefix) => | ||
Validations.checkIsSame( | ||
secretKey.length, | ||
secretKeyBytes, | ||
'${namePrefix}SecretKey', | ||
); | ||
|
||
void validateSeed(SecureKey seed) => Validations.checkIsSame( | ||
seed.length, | ||
seedBytes, | ||
'seed', | ||
); | ||
} |
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,170 @@ | ||
import 'dart:ffi'; | ||
import 'dart:typed_data'; | ||
|
||
import 'package:meta/meta.dart'; | ||
|
||
import '../../api/key_pair.dart'; | ||
import '../../api/kx.dart'; | ||
import '../../api/secure_key.dart'; | ||
import '../../api/sodium_exception.dart'; | ||
import '../bindings/libsodium.ffi.dart'; | ||
import '../bindings/memory_protection.dart'; | ||
import '../bindings/secure_key_native.dart'; | ||
import '../bindings/sodium_pointer.dart'; | ||
import 'helpers/keygen_mixin.dart'; | ||
import 'secure_key_ffi.dart'; | ||
|
||
@internal | ||
class KxFFI with KxValidations, KeygenMixin implements Kx { | ||
final LibSodiumFFI sodium; | ||
|
||
KxFFI(this.sodium); | ||
|
||
@override | ||
int get publicKeyBytes => sodium.crypto_kx_publickeybytes(); | ||
|
||
@override | ||
int get secretKeyBytes => sodium.crypto_kx_secretkeybytes(); | ||
|
||
@override | ||
int get seedBytes => sodium.crypto_kx_seedbytes(); | ||
|
||
@override | ||
int get sessionKeyBytes => sodium.crypto_kx_sessionkeybytes(); | ||
|
||
@override | ||
KeyPair keyPair() => keyPairImpl( | ||
sodium: sodium, | ||
secretKeyBytes: secretKeyBytes, | ||
publicKeyBytes: publicKeyBytes, | ||
implementation: sodium.crypto_kx_keypair, | ||
); | ||
|
||
@override | ||
KeyPair seedKeyPair(SecureKey seed) { | ||
validateSeed(seed); | ||
return seedKeyPairImpl( | ||
sodium: sodium, | ||
seed: seed, | ||
secretKeyBytes: secretKeyBytes, | ||
publicKeyBytes: publicKeyBytes, | ||
implementation: sodium.crypto_kx_seed_keypair, | ||
); | ||
} | ||
|
||
@override | ||
SessionKeys clientSessionKeys({ | ||
required Uint8List clientPublicKey, | ||
required SecureKey clientSecretKey, | ||
required Uint8List serverPublicKey, | ||
}) { | ||
validatePublicKey(clientPublicKey, 'client'); | ||
validateSecretKey(clientSecretKey, 'client'); | ||
validatePublicKey(serverPublicKey, 'server'); | ||
|
||
SecureKeyFFI? rxKey; | ||
SecureKeyFFI? txKey; | ||
SodiumPointer<Uint8>? clientPublicKeyPtr; | ||
SodiumPointer<Uint8>? serverPublicKeyPtr; | ||
try { | ||
rxKey = SecureKeyFFI.alloc(sodium, sessionKeyBytes); | ||
txKey = SecureKeyFFI.alloc(sodium, sessionKeyBytes); | ||
clientPublicKeyPtr = clientPublicKey.toSodiumPointer( | ||
sodium, | ||
memoryProtection: MemoryProtection.readOnly, | ||
); | ||
serverPublicKeyPtr = serverPublicKey.toSodiumPointer( | ||
sodium, | ||
memoryProtection: MemoryProtection.readOnly, | ||
); | ||
|
||
final result = rxKey.runUnlockedNative( | ||
(rxKeyPtr) => txKey!.runUnlockedNative( | ||
(txKeyPtr) => clientSecretKey.runUnlockedNative( | ||
sodium, | ||
(clientSecretKeyPtr) => sodium.crypto_kx_client_session_keys( | ||
rxKeyPtr.ptr, | ||
txKeyPtr.ptr, | ||
clientPublicKeyPtr!.ptr, | ||
clientSecretKeyPtr.ptr, | ||
serverPublicKeyPtr!.ptr, | ||
), | ||
), | ||
writable: true, | ||
), | ||
writable: true, | ||
); | ||
SodiumException.checkSucceededInt(result); | ||
|
||
return SessionKeys( | ||
rx: rxKey, | ||
tx: txKey, | ||
); | ||
} catch (e) { | ||
rxKey?.dispose(); | ||
txKey?.dispose(); | ||
rethrow; | ||
} finally { | ||
clientPublicKeyPtr?.dispose(); | ||
serverPublicKeyPtr?.dispose(); | ||
} | ||
} | ||
|
||
@override | ||
SessionKeys serverSessionKeys({ | ||
required Uint8List serverPublicKey, | ||
required SecureKey serverSecretKey, | ||
required Uint8List clientPublicKey, | ||
}) { | ||
validatePublicKey(serverPublicKey, 'server'); | ||
validateSecretKey(serverSecretKey, 'server'); | ||
validatePublicKey(clientPublicKey, 'client'); | ||
|
||
SecureKeyFFI? rxKey; | ||
SecureKeyFFI? txKey; | ||
SodiumPointer<Uint8>? serverPublicKeyPtr; | ||
SodiumPointer<Uint8>? clientPublicKeyPtr; | ||
try { | ||
rxKey = SecureKeyFFI.alloc(sodium, sessionKeyBytes); | ||
txKey = SecureKeyFFI.alloc(sodium, sessionKeyBytes); | ||
serverPublicKeyPtr = serverPublicKey.toSodiumPointer( | ||
sodium, | ||
memoryProtection: MemoryProtection.readOnly, | ||
); | ||
clientPublicKeyPtr = clientPublicKey.toSodiumPointer( | ||
sodium, | ||
memoryProtection: MemoryProtection.readOnly, | ||
); | ||
|
||
final result = rxKey.runUnlockedNative( | ||
(rxKeyPtr) => txKey!.runUnlockedNative( | ||
(txKeyPtr) => serverSecretKey.runUnlockedNative( | ||
sodium, | ||
(serverSecretKeyPtr) => sodium.crypto_kx_server_session_keys( | ||
rxKeyPtr.ptr, | ||
txKeyPtr.ptr, | ||
serverPublicKeyPtr!.ptr, | ||
serverSecretKeyPtr.ptr, | ||
clientPublicKeyPtr!.ptr, | ||
), | ||
), | ||
writable: true, | ||
), | ||
writable: true, | ||
); | ||
SodiumException.checkSucceededInt(result); | ||
|
||
return SessionKeys( | ||
rx: rxKey, | ||
tx: txKey, | ||
); | ||
} catch (e) { | ||
rxKey?.dispose(); | ||
txKey?.dispose(); | ||
rethrow; | ||
} finally { | ||
serverPublicKeyPtr?.dispose(); | ||
clientPublicKeyPtr?.dispose(); | ||
} | ||
} | ||
} |
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
Oops, something went wrong.