Skip to content

Commit

Permalink
add kx APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
Skycoder42 committed Jun 23, 2021
1 parent d224401 commit 39d5ac7
Show file tree
Hide file tree
Showing 20 changed files with 1,388 additions and 4 deletions.
4 changes: 4 additions & 0 deletions melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ scripts:
test:integration:js:
run: dart pub global run melos exec -- make -f ../../Makefile integration-tests-js
description: Run integration tests in all projects (JS only)

doc:
run: dart pub global run melos exec -- make -f ../../Makefile doc
description: Create API-documentation in all projects

verify:
run: dart pub global run melos exec -c1 -- make -f ../../Makefile verify
Expand Down
5 changes: 5 additions & 0 deletions packages/sodium/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.3] - 2021-06-23
### Added
- New libsodium API: crypto_kx
- Added missing tests for crypto_kdf

## [0.2.2] - 2021-06-01
### Added
- New libsodium API:
Expand Down
2 changes: 1 addition & 1 deletion packages/sodium/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ API based on libsodium version: *1.0.18*
crypto_shorthash | ✔️ | ✔️ | https://libsodium.gitbook.io/doc/hashing/short-input_hashing
crypto_pwhash | ✔️ | ✔️ | https://libsodium.gitbook.io/doc/password_hashing/default_phf
crypto_kdf | ✔️ | ✔️ | https://libsodium.gitbook.io/doc/key_derivation
crypto_kx | 🚧 | 🚧 | https://libsodium.gitbook.io/doc/key_exchange
crypto_kx | ✔️ | ✔️ | https://libsodium.gitbook.io/doc/key_exchange
crypto_onetimeauth | ❔ | ❔ | https://libsodium.gitbook.io/doc/advanced/poly1305
crypto_scalarmult | ❔ | ❔ | https://libsodium.gitbook.io/doc/advanced/scalar_multiplication
crypto_hash_sha | ❔ | ❔ | https://libsodium.gitbook.io/doc/advanced/sha-2_hash_function
Expand Down
1 change: 1 addition & 0 deletions packages/sodium/lib/sodium.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export 'src/api/detached_cipher_result.dart';
export 'src/api/generic_hash.dart' hide GenericHashValidations;
export 'src/api/kdf.dart' hide KdfValidations;
export 'src/api/key_pair.dart';
export 'src/api/kx.dart' hide KxValidations;
export 'src/api/pwhash.dart' hide PwHashValidations;
export 'src/api/randombytes.dart';
export 'src/api/secret_box.dart' hide SecretBoxValidations;
Expand Down
6 changes: 6 additions & 0 deletions packages/sodium/lib/src/api/crypto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'auth.dart';
import 'box.dart';
import 'generic_hash.dart';
import 'kdf.dart';
import 'kx.dart';
import 'pwhash.dart';
import 'secret_box.dart';
import 'secret_stream.dart';
Expand Down Expand Up @@ -62,4 +63,9 @@ abstract class Crypto {
///
/// This provides all APIs that start with `crypto_kdf`.
Kdf get kdf;

/// An instance of [Kx].
///
/// This provides all APIs that start with `crypto_kx`.
Kx get kx;
}
117 changes: 117 additions & 0 deletions packages/sodium/lib/src/api/kx.dart
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',
);
}
5 changes: 5 additions & 0 deletions packages/sodium/lib/src/ffi/api/crypto_ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import '../../api/box.dart';
import '../../api/crypto.dart';
import '../../api/generic_hash.dart';
import '../../api/kdf.dart';
import '../../api/kx.dart';
import '../../api/pwhash.dart';
import '../../api/secret_box.dart';
import '../../api/secret_stream.dart';
Expand All @@ -17,6 +18,7 @@ import 'auth_ffi.dart';
import 'box_ffi.dart';
import 'generic_hash_ffi.dart';
import 'kdf_ffi.dart';
import 'kx_ffi.dart';
import 'pwhash_ffi.dart';
import 'secret_box_ffi.dart';
import 'secret_stream_ffi.dart';
Expand Down Expand Up @@ -58,4 +60,7 @@ class CryptoFFI implements Crypto {

@override
late final Kdf kdf = KdfFFI(sodium);

@override
late final Kx kx = KxFFI(sodium);
}
170 changes: 170 additions & 0 deletions packages/sodium/lib/src/ffi/api/kx_ffi.dart
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();
}
}
}
5 changes: 5 additions & 0 deletions packages/sodium/lib/src/js/api/crypto_js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import '../../api/box.dart';
import '../../api/crypto.dart';
import '../../api/generic_hash.dart';
import '../../api/kdf.dart';
import '../../api/kx.dart';
import '../../api/pwhash.dart';
import '../../api/secret_box.dart';
import '../../api/secret_stream.dart';
Expand All @@ -17,6 +18,7 @@ import 'auth_js.dart';
import 'box_js.dart';
import 'generic_hash_js.dart';
import 'kdf_js.dart';
import 'kx_js.dart';
import 'pwhash_js.dart';
import 'secret_box_js.dart';
import 'secret_stream_js.dart';
Expand Down Expand Up @@ -58,4 +60,7 @@ class CryptoJS implements Crypto {

@override
late final Kdf kdf = KdfJS(sodium);

@override
late final Kx kx = KxJS(sodium);
}
Loading

0 comments on commit 39d5ac7

Please sign in to comment.