Skip to content

Commit

Permalink
feat(dart/catalyst_cose): Catalyst COSE_SIGN support (#1374)
Browse files Browse the repository at this point in the history
* refactor!: extract signer and verifier algorithms

* feat: add new COSE_SIGN1 implementation

* feat: add COSE_SIGN structure

* style: spelling

* fix: tests

* chore: code cleanup
  • Loading branch information
dtscalac authored Dec 12, 2024
1 parent 51e5b14 commit 2dfd4c3
Show file tree
Hide file tree
Showing 16 changed files with 1,265 additions and 330 deletions.
2 changes: 2 additions & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ codepoints
collabs
commitlog
concatcp
COSE
coti
coverallsapp
CQLSH
Expand Down Expand Up @@ -289,6 +290,7 @@ tojunit
Traceback
traefik
trailings
tstr
TXNZD
txos
Typer
Expand Down
88 changes: 76 additions & 12 deletions catalyst_voices/packages/libs/catalyst_cose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,40 @@ dependencies:
// ignore_for_file: avoid_print

import 'dart:convert';
import 'dart:typed_data';

import 'package:catalyst_cose/catalyst_cose.dart';
import 'package:cbor/cbor.dart';
import 'package:convert/convert.dart';
import 'package:cryptography/cryptography.dart';

Future<void> main() async {
await _coseSign1();
await _coseSign();
}

Future<void> _coseSign1() async {
final algorithm = Ed25519();
final keyPair = await algorithm.newKeyPairFromSeed(List.filled(32, 0));
final privateKey = await keyPair.extractPrivateKeyBytes();
final publicKey = await keyPair.extractPublicKey().then((e) => e.bytes);

final payload = utf8.encode('This is the content.');

final coseSign1 = await CatalystCose.sign1(
privateKey: privateKey,
payload: payload,
kid: CborBytes(publicKey),
final signerVerifier = _SignerVerifier(algorithm, keyPair);

final coseSign1 = await CoseSign1.sign(
protectedHeaders: CoseHeaders.protected(
alg: const IntValue(CoseValues.eddsaAlg),
kid: hex.encode(publicKey),
),
unprotectedHeaders: const CoseHeaders.unprotected(),
signer: signerVerifier,
payload: utf8.encode('This is the content.'),
);

final verified = await CatalystCose.verifyCoseSign1(
coseSign1: coseSign1,
publicKey: publicKey,
final verified = await coseSign1.verify(
verifier: signerVerifier,
);

print('COSE_SIGN1:');
print(hex.encode(cbor.encode(coseSign1)));
print(hex.encode(cbor.encode(coseSign1.toCbor())));
print('verified: $verified');

assert(
Expand All @@ -67,6 +74,63 @@ Future<void> main() async {
'signed by the owner of the given public key',
);
}

Future<void> _coseSign() async {
final algorithm = Ed25519();
final keyPair = await algorithm.newKeyPairFromSeed(List.filled(32, 0));
final publicKey = await keyPair.extractPublicKey().then((e) => e.bytes);
final signerVerifier = _SignerVerifier(algorithm, keyPair);

final coseSign = await CoseSign.sign(
protectedHeaders: CoseHeaders.protected(
alg: const IntValue(CoseValues.eddsaAlg),
kid: hex.encode(publicKey),
),
unprotectedHeaders: const CoseHeaders.unprotected(),
signers: [signerVerifier],
payload: utf8.encode('This is the content.'),
);

final verified = await coseSign.verify(
verifiers: [signerVerifier],
);

print('COSE_SIGN:');
print(hex.encode(cbor.encode(coseSign.toCbor())));
print('verified: $verified');

assert(
verified,
'The signature proves that given COSE_SIGN structure has been '
'signed by the owner of the given public key',
);
}

final class _SignerVerifier
implements CatalystCoseSigner, CatalystCoseVerifier {
final SignatureAlgorithm _algorithm;
final SimpleKeyPair _keyPair;

const _SignerVerifier(this._algorithm, this._keyPair);

@override
Future<Uint8List> sign(Uint8List data) async {
final signature = await _algorithm.sign(data, keyPair: _keyPair);
return Uint8List.fromList(signature.bytes);
}

@override
Future<bool> verify(Uint8List data, Uint8List signature) async {
final publicKey = await _keyPair.extractPublicKey();
return _algorithm.verify(
data,
signature: Signature(
signature,
publicKey: SimplePublicKey(publicKey.bytes, type: KeyPairType.ed25519),
),
);
}
}
```

## Limitations
Expand Down
86 changes: 75 additions & 11 deletions catalyst_voices/packages/libs/catalyst_cose/example/main.dart
Original file line number Diff line number Diff line change
@@ -1,33 +1,40 @@
// ignore_for_file: avoid_print

import 'dart:convert';
import 'dart:typed_data';

import 'package:catalyst_cose/catalyst_cose.dart';
import 'package:cbor/cbor.dart';
import 'package:convert/convert.dart';
import 'package:cryptography/cryptography.dart';

Future<void> main() async {
await _coseSign1();
await _coseSign();
}

Future<void> _coseSign1() async {
final algorithm = Ed25519();
final keyPair = await algorithm.newKeyPairFromSeed(List.filled(32, 0));
final privateKey = await keyPair.extractPrivateKeyBytes();
final publicKey = await keyPair.extractPublicKey().then((e) => e.bytes);
final signerVerifier = _SignerVerifier(algorithm, keyPair);

final payload = utf8.encode('This is the content.');

final coseSign1 = await CatalystCose.sign1(
privateKey: privateKey,
payload: payload,
kid: CborBytes(publicKey),
final coseSign1 = await CoseSign1.sign(
protectedHeaders: CoseHeaders.protected(
alg: const IntValue(CoseValues.eddsaAlg),
kid: hex.encode(publicKey),
),
unprotectedHeaders: const CoseHeaders.unprotected(),
signer: signerVerifier,
payload: utf8.encode('This is the content.'),
);

final verified = await CatalystCose.verifyCoseSign1(
coseSign1: coseSign1,
publicKey: publicKey,
final verified = await coseSign1.verify(
verifier: signerVerifier,
);

print('COSE_SIGN1:');
print(hex.encode(cbor.encode(coseSign1)));
print(hex.encode(cbor.encode(coseSign1.toCbor())));
print('verified: $verified');

assert(
Expand All @@ -36,3 +43,60 @@ Future<void> main() async {
'signed by the owner of the given public key',
);
}

Future<void> _coseSign() async {
final algorithm = Ed25519();
final keyPair = await algorithm.newKeyPairFromSeed(List.filled(32, 0));
final publicKey = await keyPair.extractPublicKey().then((e) => e.bytes);
final signerVerifier = _SignerVerifier(algorithm, keyPair);

final coseSign = await CoseSign.sign(
protectedHeaders: CoseHeaders.protected(
alg: const IntValue(CoseValues.eddsaAlg),
kid: hex.encode(publicKey),
),
unprotectedHeaders: const CoseHeaders.unprotected(),
signers: [signerVerifier],
payload: utf8.encode('This is the content.'),
);

final verified = await coseSign.verify(
verifiers: [signerVerifier],
);

print('COSE_SIGN:');
print(hex.encode(cbor.encode(coseSign.toCbor())));
print('verified: $verified');

assert(
verified,
'The signature proves that given COSE_SIGN structure has been '
'signed by the owner of the given public key',
);
}

final class _SignerVerifier
implements CatalystCoseSigner, CatalystCoseVerifier {
final SignatureAlgorithm _algorithm;
final SimpleKeyPair _keyPair;

const _SignerVerifier(this._algorithm, this._keyPair);

@override
Future<Uint8List> sign(Uint8List data) async {
final signature = await _algorithm.sign(data, keyPair: _keyPair);
return Uint8List.fromList(signature.bytes);
}

@override
Future<bool> verify(Uint8List data, Uint8List signature) async {
final publicKey = await _keyPair.extractPublicKey();
return _algorithm.verify(
data,
signature: Signature(
signature,
publicKey: SimplePublicKey(publicKey.bytes, type: KeyPairType.ed25519),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export 'src/catalyst_cose.dart';
export 'src/cose_constants.dart';
export 'src/cose_sign.dart';
export 'src/cose_sign1.dart';
export 'src/types/cose_headers.dart';
export 'src/types/string_or_int.dart';
export 'src/types/uuid.dart';
Loading

0 comments on commit 2dfd4c3

Please sign in to comment.