Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging Process #1 from sd-jwt-ts #60

Merged
merged 25 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d55879c
Revert "fix: the bytes of the output of the hash function must be bas…
lukasjhan Feb 11, 2024
d611fa7
feat: migrate base64url
lukasjhan Feb 11, 2024
061c3d2
fix: restore tests
lukasjhan Feb 11, 2024
c0abd2e
feat: fix decoy and disclosure
lukasjhan Feb 11, 2024
cf7784a
feat: fix digest of encoded disclosure
lukasjhan Feb 12, 2024
c17a886
chore: Apply prettier
lukasjhan Feb 12, 2024
716b8c7
feat: Add test for utin8array encoding
lukasjhan Feb 12, 2024
4c15ffc
feat: Remove jose in jwt sign and verify
lukasjhan Feb 12, 2024
b29e314
feat: Remove jose in types
lukasjhan Feb 12, 2024
915278b
feat: Fix sdjwt tests
lukasjhan Feb 12, 2024
837b193
feat: implement new interface
lukasjhan Feb 12, 2024
9a375a8
feat: Fix e2e tests and type
lukasjhan Feb 12, 2024
4f7337d
feat: Fix index tests
lukasjhan Feb 12, 2024
2b2874d
refactor: using constant
lukasjhan Feb 12, 2024
da5b16e
feat: add tests for crypto functions
lukasjhan Feb 12, 2024
d6b1285
feat: Add default sha256 function
lukasjhan Feb 12, 2024
4511026
feat: fix sign_alg, hash_alg config
lukasjhan Feb 12, 2024
162585c
feat: fix examples
lukasjhan Feb 12, 2024
0168470
doc: Add dependencies
lukasjhan Feb 12, 2024
ce0aacc
doc: add decoding example
lukasjhan Feb 12, 2024
097c4a3
refactor: Remove base64 function overloading
lukasjhan Feb 13, 2024
25d0ef0
refactor: unify variable convention
lukasjhan Feb 13, 2024
613f4fe
Merge branch 'main' into dev/merge1
lukasjhan Feb 13, 2024
3b34b0c
feat: Add utf8 encode function and tests
lukasjhan Feb 13, 2024
fa6e0d7
test: Remove dup test
lukasjhan Feb 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ Check out more details in our [documentation](https://github.com/openwallet-foun

## Dependencies

- [jose](https://github.com/panva/jose)
- "@noble/hashes": "1.0.0",
- pure js hash algorithm implementation with security audit (v1.0.0)
- "js-base64": "^3.7.6"
- pure js base64 implementation

## Build

Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pnpm run all
- sdjwtobject: Example of using SD JWT Object
- decoy: Example of adding decoy digest in SD JWT
- kb: key binding example in SD JWT
- decode: Decoding example of a SD JWT sample

### Variables In Examples

Expand Down
39 changes: 20 additions & 19 deletions examples/all.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';
import Crypto from 'node:crypto';

export const createKeyPair = () => {
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
return { privateKey, publicKey };
};
import { DisclosureFrame, SDJwtInstance } from '@hopae/sd-jwt';
import { createSignerVerifier, digest, generateSalt } from './utils';

(async () => {
const { privateKey, publicKey } = createKeyPair();
const { signer, verifier } = createSignerVerifier();

// Create SDJwt instance for use
const sdjwt = new SDJwtInstance({
signer,
verifier,
signAlg: 'EdDSA',
hasher: digest,
hashAlg: 'SHA-256',
saltGenerator: generateSalt,
});

// Issuer Define the claims object with the user's information
const claims = {
Expand Down Expand Up @@ -47,26 +52,26 @@ export const createKeyPair = () => {

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await sdjwt.issue(claims, { privateKey }, disclosureFrame);
const credential = await sdjwt.issue(claims, disclosureFrame);
console.log('encodedJwt:', credential);

// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const validated = await sdjwt.validate(credential, { publicKey });
const validated = await sdjwt.validate(credential);
console.log('validated:', validated);

// You can decode the SD JWT to get the payload and the disclosures
const sdJwtToken = sdjwt.decode(credential);
const sdJwtToken = await sdjwt.decode(credential);

// You can get the keys of the claims from the decoded SD JWT
const keys = await sdJwtToken.keys();
const keys = await sdJwtToken.keys(digest);
console.log({ keys });

// You can get the claims from the decoded SD JWT
const payloads = await sdJwtToken.getClaims();
const payloads = await sdJwtToken.getClaims(digest);

// You can get the presentable keys from the decoded SD JWT
const presentableKeys = await sdJwtToken.presentableKeys();
const presentableKeys = await sdJwtToken.presentableKeys(digest);

console.log({
payloads: JSON.stringify(payloads, null, 2),
Expand Down Expand Up @@ -94,10 +99,6 @@ export const createKeyPair = () => {

// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await sdjwt.verify(
credential,
{ publicKey },
requiredClaims,
);
const verified = await sdjwt.verify(credential, requiredClaims);
console.log('verified:', verified);
})();
32 changes: 17 additions & 15 deletions examples/basic.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';
import Crypto from 'node:crypto';

export const createKeyPair = () => {
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
return { privateKey, publicKey };
};
import { DisclosureFrame, SDJwtInstance } from '@hopae/sd-jwt';
import { createSignerVerifier, digest, generateSalt } from './utils';

(async () => {
const { privateKey, publicKey } = createKeyPair();
const { signer, verifier } = createSignerVerifier();

// Create SDJwt instance for use
const sdjwt = new SDJwtInstance({
signer,
verifier,
signAlg: 'EdDSA',
hasher: digest,
hashAlg: 'SHA-256',
saltGenerator: generateSalt,
});

// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
Expand All @@ -23,11 +29,11 @@ export const createKeyPair = () => {

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await sdjwt.issue(claims, { privateKey }, disclosureFrame);
const credential = await sdjwt.issue(claims, disclosureFrame);

// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const valid = await sdjwt.validate(credential, { publicKey });
const valid = await sdjwt.validate(credential);

// Holder Define the presentation frame to specify which claims should be presented
// The list of presented claims must be a subset of the disclosed claims
Expand All @@ -43,10 +49,6 @@ export const createKeyPair = () => {

// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await sdjwt.verify(
presentation,
{ publicKey },
requiredClaims,
);
const verified = await sdjwt.verify(presentation, requiredClaims);
console.log(verified);
})();
66 changes: 21 additions & 45 deletions examples/custom.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';
import Crypto from 'node:crypto';

export const salt = (length: number): string => {
const saltBytes = Crypto.randomBytes(length);
const salt = saltBytes.toString('hex');
return salt;
};

export const digest = async (
data: string,
algorithm: string = 'SHA-256',
): Promise<string> => {
const hash = Crypto.createHash(algorithm);
hash.update(data);
return hash.digest('hex');
};

export const createKeyPair = () => {
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
return { privateKey, publicKey };
};
import { DisclosureFrame, SDJwtInstance } from '@hopae/sd-jwt';
import { createSignerVerifier, digest, generateSalt } from './utils';

(async () => {
// You can create a custom SDJwt instance with your own hasher and salt generator
const SDJwtInstance = sdjwt.create({ hasher: digest, saltGenerator: salt });

const { privateKey, publicKey } = createKeyPair();
const { signer, verifier } = createSignerVerifier();

// Create SDJwt instance for use
const sdjwt = new SDJwtInstance({
signer,
verifier,
signAlg: 'EdDSA',
hasher: digest,
hashAlg: 'SHA-256',
saltGenerator: generateSalt,
});

// Issuer Define the claims object with the user's information
const claims = {
Expand All @@ -42,30 +29,26 @@ export const createKeyPair = () => {

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await SDJwtInstance.issue(
claims,
{ privateKey },
disclosureFrame,
);
const credential = await sdjwt.issue(claims, disclosureFrame);
console.log('encodedJwt:', credential);

// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const validated = await SDJwtInstance.validate(credential, { publicKey });
const validated = await sdjwt.validate(credential);
console.log('validated:', validated);

// You can decode the SD JWT to get the payload and the disclosures
const sdJwtToken = SDJwtInstance.decode(credential);
const sdJwtToken = await sdjwt.decode(credential);

// You can get the keys of the claims from the decoded SD JWT
const keys = await sdJwtToken.keys();
const keys = await sdJwtToken.keys(digest);
console.log({ keys });

// You can get the claims from the decoded SD JWT
const payloads = await sdJwtToken.getClaims();
const payloads = await sdJwtToken.getClaims(digest);

// You can get the presentable keys from the decoded SD JWT
const presentableKeys = await sdJwtToken.presentableKeys();
const presentableKeys = await sdJwtToken.presentableKeys(digest);

console.log({
payloads: JSON.stringify(payloads, null, 2),
Expand All @@ -85,21 +68,14 @@ export const createKeyPair = () => {

// Create a presentation using the issued credential and the presentation frame
// return a Encoded SD JWT. Holder send the presentation to the verifier
const presentation = await SDJwtInstance.present(
credential,
presentationFrame,
);
const presentation = await sdjwt.present(credential, presentationFrame);
console.log('presentedSDJwt:', presentation);

// Verifier Define the required claims that need to be verified in the presentation
const requiredClaims = ['firstname', 'id'];

// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await SDJwtInstance.verify(
presentation,
{ publicKey },
requiredClaims,
);
const verified = await sdjwt.verify(presentation, requiredClaims);
console.log('verified:', verified);
})();
35 changes: 18 additions & 17 deletions examples/custom_header.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';
import Crypto from 'node:crypto';

export const createKeyPair = () => {
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
return { privateKey, publicKey };
};
import { DisclosureFrame, SDJwtInstance } from '@hopae/sd-jwt';
import { createSignerVerifier, digest, generateSalt } from './utils';

(async () => {
const { privateKey, publicKey } = createKeyPair();
const { signer, verifier } = createSignerVerifier();

// Create SDJwt instance for use
const sdjwt = new SDJwtInstance({
signer,
verifier,
signAlg: 'EdDSA',
hasher: digest,
hashAlg: 'SHA-256',
saltGenerator: generateSalt,
});

// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
Expand All @@ -23,17 +29,12 @@ export const createKeyPair = () => {

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await sdjwt.issue(
claims,
{ privateKey },
disclosureFrame,
{
header: { typ: 'vc+sd-jwt', custom: 'data' }, // You can add custom header data to the SD JWT
},
);
const credential = await sdjwt.issue(claims, disclosureFrame, {
header: { typ: 'vc+sd-jwt', custom: 'data' }, // You can add custom header data to the SD JWT
});
console.log('encodedSdjwt:', credential);

// You can check the custom header data by decoding the SD JWT
const sdJwtToken = sdjwt.decode(credential);
const sdJwtToken = await sdjwt.decode(credential);
console.log(sdJwtToken);
})();
26 changes: 26 additions & 0 deletions examples/decode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { SDJwtInstance } from '@hopae/sd-jwt';
import { createSignerVerifier, digest, generateSalt } from './utils';

(async () => {
const { signer, verifier } = createSignerVerifier();

// Create SDJwt instance for use
const sdjwt = new SDJwtInstance({
signer,
signAlg: 'EdDSA',
verifier,
hasher: digest,
saltGenerator: generateSalt,
kbSigner: signer,
kbSignAlg: 'EdDSA',
kbVerifier: verifier,
});

// this is an example of SD JWT
const data = `eyJhbGciOiAiRVMyNTYiLCAia2lkIjogImRvYy1zaWduZXItMDUtMjUtMjAyMiIsICJ0eXAiOiAidmMrc2Qtand0In0.eyJfc2QiOiBbIjA5dktySk1PbHlUV00wc2pwdV9wZE9CVkJRMk0xeTNLaHBINTE1blhrcFkiLCAiMnJzakdiYUMwa3k4bVQwcEpyUGlvV1RxMF9kYXcxc1g3NnBvVWxnQ3diSSIsICJFa084ZGhXMGRIRUpidlVIbEVfVkNldUM5dVJFTE9pZUxaaGg3WGJVVHRBIiwgIklsRHpJS2VpWmREd3BxcEs2WmZieXBoRnZ6NUZnbldhLXNONndxUVhDaXciLCAiSnpZakg0c3ZsaUgwUjNQeUVNZmVadTZKdDY5dTVxZWhabzdGN0VQWWxTRSIsICJQb3JGYnBLdVZ1Nnh5bUphZ3ZrRnNGWEFiUm9jMkpHbEFVQTJCQTRvN2NJIiwgIlRHZjRvTGJnd2Q1SlFhSHlLVlFaVTlVZEdFMHc1cnREc3JaemZVYW9tTG8iLCAiamRyVEU4WWNiWTRFaWZ1Z2loaUFlX0JQZWt4SlFaSUNlaVVRd1k5UXF4SSIsICJqc3U5eVZ1bHdRUWxoRmxNXzNKbHpNYVNGemdsaFFHMERwZmF5UXdMVUs0Il0sICJpc3MiOiAiaHR0cHM6Ly9leGFtcGxlLmNvbS9pc3N1ZXIiLCAiaWF0IjogMTY4MzAwMDAwMCwgImV4cCI6IDE4ODMwMDAwMDAsICJkY3QiOiAiaHR0cHM6Ly9jcmVkZW50aWFscy5leGFtcGxlLmNvbS9pZGVudGl0eV9jcmVkZW50aWFsIiwgIl9zZF9hbGciOiAic2hhLTI1NiIsICJjbmYiOiB7Imp3ayI6IHsia3R5IjogIkVDIiwgImNydiI6ICJQLTI1NiIsICJ4IjogIlRDQUVSMTladnUzT0hGNGo0VzR2ZlNWb0hJUDFJTGlsRGxzN3ZDZUdlbWMiLCAieSI6ICJaeGppV1diWk1RR0hWV0tWUTRoYlNJaXJzVmZ1ZWNDRTZ0NGpUOUYySFpRIn19fQ.b036DutqQ72WszrCq0GuqZnbws3MApQyzA41I5DSJmenUfsADtqW8FbI_N04FP1wZDF_JtV6a6Ke3Z7apkoTLA~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImZhbWlseV9uYW1lIiwgIkRvZSJd~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgImVtYWlsIiwgImpvaG5kb2VAZXhhbXBsZS5jb20iXQ~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgInBob25lX251bWJlciIsICIrMS0yMDItNTU1LTAxMDEiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgImFkZHJlc3MiLCB7InN0cmVldF9hZGRyZXNzIjogIjEyMyBNYWluIFN0IiwgImxvY2FsaXR5IjogIkFueXRvd24iLCAicmVnaW9uIjogIkFueXN0YXRlIiwgImNvdW50cnkiOiAiVVMifV0~WyJBSngtMDk1VlBycFR0TjRRTU9xUk9BIiwgImJpcnRoZGF0ZSIsICIxOTQwLTAxLTAxIl0~WyJQYzMzSk0yTGNoY1VfbEhnZ3ZfdWZRIiwgImlzX292ZXJfMTgiLCB0cnVlXQ~WyJHMDJOU3JRZmpGWFE3SW8wOXN5YWpBIiwgImlzX292ZXJfMjEiLCB0cnVlXQ~WyJsa2x4RjVqTVlsR1RQVW92TU5JdkNBIiwgImlzX292ZXJfNjUiLCB0cnVlXQ~`;
const decodedObject = await sdjwt.decode(data);
console.log(decodedObject);

const claims = await sdjwt.getClaims(data);
console.log(claims);
})();
25 changes: 15 additions & 10 deletions examples/decoy.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';
import Crypto from 'node:crypto';

export const createKeyPair = () => {
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
return { privateKey, publicKey };
};
import { DisclosureFrame, SDJwtInstance } from '@hopae/sd-jwt';
import { createSignerVerifier, digest, generateSalt } from './utils';

(async () => {
const { privateKey, publicKey } = createKeyPair();
const { signer, verifier } = createSignerVerifier();

// Create SDJwt instance for use
const sdjwt = new SDJwtInstance({
signer,
verifier,
signAlg: 'EdDSA',
hasher: digest,
hashAlg: 'SHA-256',
saltGenerator: generateSalt,
});
// Issuer Define the claims object with the user's information
const claims = {
lastname: 'Doe',
Expand All @@ -20,10 +25,10 @@ export const createKeyPair = () => {
_sd: ['id'],
_sd_decoy: 1, // 1 decoy digest will be added in SD JWT
};
const credential = await sdjwt.issue(claims, { privateKey }, disclosureFrame);
const credential = await sdjwt.issue(claims, disclosureFrame);
console.log('encodedSdjwt:', credential);

// You can check the decoy digest in the SD JWT by decoding it
const sdJwtToken = sdjwt.decode(credential);
const sdJwtToken = await sdjwt.decode(credential);
console.log(sdJwtToken);
})();
Loading