Skip to content

Commit a150627

Browse files
Nanne Baarsnbaars
authored andcommitted
Implement algorithm lucidity
1 parent 832c14e commit a150627

File tree

18 files changed

+186
-84
lines changed

18 files changed

+186
-84
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.paseto4j.commons;
2+
3+
import static org.paseto4j.commons.Conditions.verify;
4+
5+
public abstract class Key {
6+
7+
public byte[] material;
8+
public Version version;
9+
10+
public Key(byte[] keyMaterial, Version version) {
11+
this.material = keyMaterial;
12+
this.version = version;
13+
}
14+
15+
public Key(byte[] keyMaterial, Version version, int size) {
16+
verify(keyMaterial.length == 32, "key should be " + size + " bytes");
17+
18+
this.material = keyMaterial;
19+
this.version = version;
20+
}
21+
22+
abstract public boolean isValidFor(Version v, Purpose p);
23+
24+
public boolean hasLength(int length) {
25+
return length == material.length;
26+
}
27+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.paseto4j.commons;
2+
3+
public class PrivateKey extends Key {
4+
public PrivateKey(byte[] keyMaterial, Version version) {
5+
super(keyMaterial, version);
6+
}
7+
8+
public boolean isValidFor(Version v, Purpose p) {
9+
return v == this.version && p == Purpose.PURPOSE_PUBLIC;
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.paseto4j.commons;
2+
3+
public class PublicKey extends Key {
4+
public PublicKey(byte[] keyMaterial, Version version) {
5+
super(keyMaterial, version);
6+
}
7+
8+
public boolean isValidFor(Version v, Purpose p) {
9+
return v == this.version && p == Purpose.PURPOSE_PUBLIC;
10+
}
11+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package org.paseto4j.commons;
2+
3+
public enum Purpose {PURPOSE_LOCAL, PURPOSE_PUBLIC};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.paseto4j.commons;
2+
3+
public class SecretKey extends Key {
4+
public SecretKey(byte[] keyMaterial, Version version) {
5+
super(keyMaterial, version, 32);
6+
}
7+
8+
public boolean isValidFor(Version v, Purpose p) {
9+
return v == this.version && p == Purpose.PURPOSE_LOCAL;
10+
}
11+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.paseto4j.commons;
2+
3+
public enum Version {V1, V2};
4+

examples/src/main/java/org/paseto4j/version2/Version1.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@
2424

2525
package org.paseto4j.version2;
2626

27+
import org.paseto4j.commons.PrivateKey;
28+
import org.paseto4j.commons.PublicKey;
29+
import org.paseto4j.commons.SecretKey;
2730
import org.paseto4j.version1.Paseto;
2831

2932
import java.security.*;
3033

34+
import static org.paseto4j.commons.Version.V1;
35+
3136
public class Version1 {
3237

3338
private static final String TOKEN = "{\"data\":\"this is a signed message\",\"expires\":\"2019-01-01T00:00:00+00:00\"}";
@@ -47,21 +52,21 @@ public static void main(String[] args) throws SignatureException {
4752
private static void exampleV1Public() throws SignatureException {
4853
KeyPair keyPair = generateKeyPair();
4954

50-
String signedToken = Paseto.sign(keyPair.getPrivate().getEncoded(), TOKEN, FOOTER);
55+
String signedToken = Paseto.sign(new PrivateKey(keyPair.getPrivate().getEncoded(), V1), TOKEN, FOOTER);
5156
System.out.println("Signed token is: " + signedToken);
5257

53-
String token = Paseto.parse(keyPair.getPublic().getEncoded(), signedToken, FOOTER);
58+
String token = Paseto.parse(new PublicKey(keyPair.getPublic().getEncoded(), V1), signedToken, FOOTER);
5459
System.out.println("Signature is valid, token is: " + token);
5560
}
5661

5762
private static void exampleV1PublicSignatureInvalid() throws SignatureException {
5863
KeyPair keyPair1 = generateKeyPair();
5964
KeyPair keyPair2 = generateKeyPair();
6065

61-
String signedToken = Paseto.sign(keyPair1.getPrivate().getEncoded(), TOKEN, FOOTER);
66+
String signedToken = Paseto.sign(new PrivateKey(keyPair1.getPrivate().getEncoded(), V1), TOKEN, FOOTER);
6267
System.out.println("Signed token is: " + signedToken);
6368

64-
String token = Paseto.parse(keyPair2.getPublic().getEncoded(), signedToken, FOOTER);
69+
String token = Paseto.parse(new PublicKey(keyPair2.getPublic().getEncoded(), V1), signedToken, FOOTER);
6570
System.out.println("Signature is valid, token is: " + token);
6671
}
6772

@@ -77,10 +82,10 @@ private static KeyPair generateKeyPair() {
7782

7883
private static void exampleV1Local() {
7984
byte[] secretKey = SecureRandom.getSeed(32);
80-
String encryptedToken = Paseto.encrypt(secretKey, TOKEN, FOOTER);
85+
String encryptedToken = Paseto.encrypt(new SecretKey(secretKey, V1), TOKEN, FOOTER);
8186
System.out.println("Encrypted token is: " + encryptedToken);
8287

83-
String decryptedToken = Paseto.decrypt(secretKey, encryptedToken, FOOTER);
88+
String decryptedToken = Paseto.decrypt(new SecretKey(secretKey, V1), encryptedToken, FOOTER);
8489
System.out.println("Decrypted token is: " + decryptedToken);
8590
}
8691

examples/src/main/java/org/paseto4j/version2/Version2.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import org.apache.tuweni.bytes.Bytes;
44
import org.apache.tuweni.crypto.sodium.Signature;
5+
import org.paseto4j.commons.PrivateKey;
6+
import org.paseto4j.commons.PublicKey;
7+
import org.paseto4j.commons.Version;
58

69
import java.security.SignatureException;
710

@@ -14,8 +17,8 @@ public static void main(String... args) throws SignatureException {
1417
private void signToken() throws SignatureException {
1518
var seed = Bytes.random(32).toArray();
1619
var keyPair = Signature.KeyPair.fromSeed(Signature.Seed.fromBytes(seed));
17-
var publicKey = new byte[32];
18-
var privateKey = keyPair.secretKey().bytesArray();
20+
var publicKey = new PublicKey(keyPair.publicKey().bytesArray(), Version.V2);
21+
var privateKey = new PrivateKey(keyPair.secretKey().bytesArray(), Version.V2);
1922

2023
String signedToken = Paseto.sign(
2124
privateKey,

version1/src/main/java/org/paseto4j/version1/Paseto.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,42 @@
2424

2525
package org.paseto4j.version1;
2626

27+
import org.paseto4j.commons.PrivateKey;
28+
import org.paseto4j.commons.PublicKey;
29+
import org.paseto4j.commons.SecretKey;
30+
2731
import java.security.SignatureException;
2832

2933
public class Paseto {
3034

31-
private Paseto() {}
35+
private Paseto() {
36+
}
3237

3338
/**
3439
* https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#encrypt
3540
*/
36-
public static String encrypt(byte[] key, String payload, String footer) {
41+
public static String encrypt(SecretKey key, String payload, String footer) {
3742
return org.paseto4j.version1.PasetoLocal.encrypt(key, payload, footer);
3843
}
3944

4045
/**
4146
* https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#decrypt
4247
*/
43-
public static String decrypt(byte[] key, String signedMessage, String footer) {
48+
public static String decrypt(SecretKey key, String signedMessage, String footer) {
4449
return PasetoLocal.decrypt(key, signedMessage, footer);
4550
}
4651

4752
/**
4853
* Sign the token, https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#sign
4954
*/
50-
public static String sign(byte[] privateKey, String payload, String footer) {
55+
public static String sign(PrivateKey privateKey, String payload, String footer) {
5156
return PasetoPublic.sign(privateKey, payload, footer);
5257
}
5358

5459
/**
5560
* Parse the token, https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#verify
5661
*/
57-
public static String parse(byte[] publicKey, String signedMessage, String footer) throws SignatureException {
62+
public static String parse(PublicKey publicKey, String signedMessage, String footer) throws SignatureException {
5863
return PasetoPublic.parse(publicKey, signedMessage, footer);
5964
}
6065
}

version1/src/main/java/org/paseto4j/version1/PasetoLocal.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
package org.paseto4j.version1;
2626

2727
import org.bouncycastle.jce.provider.BouncyCastleProvider;
28-
import org.paseto4j.commons.ByteUtils;
29-
import org.paseto4j.commons.PreAuthenticationEncoder;
28+
import org.paseto4j.commons.*;
3029

3130
import java.security.MessageDigest;
3231
import java.security.Security;
@@ -55,17 +54,17 @@ private PasetoLocal() {
5554
/**
5655
* https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#encrypt
5756
*/
58-
public static String encrypt(byte[] key, String payload, String footer) {
57+
public static String encrypt(SecretKey key, String payload, String footer) {
5958
return encrypt(key, randomBytes(), payload, footer);
6059
}
6160

6261
/**
6362
* https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#encrypt
6463
*/
65-
static String encrypt(byte[] key, byte[] randomKey, String payload, String footer) {
64+
static String encrypt(SecretKey key, byte[] randomKey, String payload, String footer) {
6665
requireNonNull(key);
6766
requireNonNull(payload);
68-
verify(key.length == 32, "key should be 32 bytes");
67+
verify(key.isValidFor(Version.V1, Purpose.PURPOSE_LOCAL), "Key is not valid for purpose and version");
6968

7069
//3
7170
byte[] nonce = getNonce(payload.getBytes(UTF_8), randomKey);
@@ -96,21 +95,21 @@ private static byte[] getNonce(byte[] payload, byte[] randomKey) {
9695
return Arrays.copyOfRange(CryptoFunctions.hmac384(randomKey, payload), 0, 32);
9796
}
9897

99-
private static byte[] encryptionKey(byte[] key, byte[] nonce) {
100-
return hkdfSha384(key, Arrays.copyOfRange(nonce, 0, 16), "paseto-encryption-key".getBytes(UTF_8));
98+
private static byte[] encryptionKey(SecretKey key, byte[] nonce) {
99+
return hkdfSha384(key.material, Arrays.copyOfRange(nonce, 0, 16), "paseto-encryption-key".getBytes(UTF_8));
101100
}
102101

103-
private static byte[] authenticationKey(byte[] key, byte[] nonce) {
104-
return hkdfSha384(key, Arrays.copyOfRange(nonce, 0, 16), "paseto-auth-key-for-aead".getBytes(UTF_8));
102+
private static byte[] authenticationKey(SecretKey key, byte[] nonce) {
103+
return hkdfSha384(key.material, Arrays.copyOfRange(nonce, 0, 16), "paseto-auth-key-for-aead".getBytes(UTF_8));
105104
}
106105

107106
/**
108107
* https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version1.md#decrypt
109108
*/
110-
static String decrypt(byte[] key, String token, String footer) {
109+
static String decrypt(SecretKey key, String token, String footer) {
111110
requireNonNull(key);
112111
requireNonNull(token);
113-
verify(key.length == 32, "Secret key should be 32 bytes");
112+
verify(key.isValidFor(Version.V1, Purpose.PURPOSE_LOCAL), "Key is not valid for purpose and version");
114113

115114
String[] tokenParts = token.split("\\.");
116115
verify(tokenParts.length == 3 || tokenParts.length == 4, "Token should contain at least 3 parts");

0 commit comments

Comments
 (0)