Skip to content

Commit 36e1a67

Browse files
committed
extends responder implementation to interop with initiator, bug fixes
1 parent 013eb05 commit 36e1a67

File tree

8 files changed

+179
-40
lines changed

8 files changed

+179
-40
lines changed

dh/implementation/initiator/initiator.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,10 +408,10 @@ func (i *Initiator) ProduceHsMsg3() (signedMsg3 []byte, err error) {
408408
i.irKey, i.riKey = NewBytes(32), NewBytes(32)
409409
//@ sharedSecretB := Abs(sharedSecret)
410410
err = KDF2Slice(i.irKey, i.riKey, sharedSecret /*@, sharedSecretB @*/)
411-
/*@
412-
ghost if err == nil {
413-
fold HandshakeCompletedPred(i.irKey, i.riKey, i.xT, i.YT)
414-
} @*/
411+
if err == nil {
412+
i.l.PrintKeys(i.irKey, i.riKey)
413+
//@ fold HandshakeCompletedPred(i.irKey, i.riKey, i.xT, i.YT)
414+
}
415415
}
416416
//@ )
417417

dh/implementation/library/io.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,10 @@ func NewError(msg string) (err error) {
3030
func (l *LibState) PrintSharedSecret(sharedSecret []byte) {
3131
fmt.Printf("Initiator & responder agreed on shared secret %x\n", sharedSecret)
3232
}
33+
34+
//@ trusted
35+
//@ preserves acc(l.Mem(), 1/16)
36+
//@ preserves acc(Mem(irKey), 1/16) && acc(Mem(riKey), 1/16)
37+
func (l *LibState) PrintKeys(irKey, riKey []byte) {
38+
fmt.Printf("IR Key %x\nRI Key %x\n", irKey, riKey)
39+
}

dh/implementation/library/marshal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func (l *LibState) MarshalMsg3(msg3 *Msg3) (res []byte, err error) {
9595
//@ ensures err == nil ==> Mem(res)
9696
//@ ensures err == nil ==> Abs(res) == by.tuple2B(by.integer32B(TransMsgTag), Abs(ciphertext))
9797
func (l *LibState) MarshalTransportMsg(ciphertext []byte) (res []byte, err error) {
98-
res = make([]byte, len(ciphertext) + 4)
98+
res = make([]byte, 4)
9999
binary.BigEndian.PutUint32(res[:4], TransMsgTag)
100100
return append(res, ciphertext...), nil
101101
}

dh/implementation/main.go

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,30 @@ package main
22

33
import "bufio"
44
import "encoding/base64"
5+
import "errors"
56
import "flag"
67
import "fmt"
78
import "os"
89
import "dh-gobra/initiator"
910
import "dh-gobra/iolib"
1011

1112
type Config struct {
13+
IsInitiator bool
1214
PrivateKey string
1315
PeerEndpoint string // <address>:<port>, e.g. "127.0.0.1:57654" (IPv4) or "[::1]:57950" (IPv6)
1416
PeerPublicKey string
1517
}
1618

1719
func parseArgs() Config {
20+
isInitiatorPtr := flag.Bool("isInitiator", false, "specifies whether this instance should act as an initiator")
1821
privateKeyPtr := flag.String("privateKey", "", "base64 encoded private key of this protocol participant")
1922
peerEndpointPtr := flag.String("endpoint", "", "<address>:<port> of the peer's endpoint")
2023
peerPublicKeyPtr := flag.String("peerPublicKey", "", "base64 encoded public key of the peer")
2124

2225
flag.Parse()
2326

2427
config := Config{
28+
IsInitiator: *isInitiatorPtr,
2529
PrivateKey: *privateKeyPtr,
2630
PeerEndpoint: *peerEndpointPtr,
2731
PeerPublicKey: *peerPublicKeyPtr,
@@ -33,97 +37,94 @@ func main() {
3337
// parse args
3438
config := parseArgs()
3539

40+
if !config.IsInitiator {
41+
reportAndExit(errors.New("responder is currently not implemented"))
42+
}
43+
3644
privateKey, peerPublicKey, err := parseKeys(config)
3745
if err != nil {
38-
os.Exit(-1)
39-
return
46+
reportAndExit(err)
4047
}
4148

4249
initiator, err := initiator.NewInitiator(privateKey, peerPublicKey)
4350
if err != nil {
44-
os.Exit(-1)
45-
return
51+
reportAndExit(err)
4652
}
4753

4854
iolib, err := iolib.NewLibState(config.PeerEndpoint)
4955
if err != nil {
50-
os.Exit(-1)
51-
return
56+
reportAndExit(err)
5257
}
5358

5459
hsMsg1, err := initiator.ProduceHsMsg1()
5560
if err != nil {
56-
os.Exit(-1)
57-
return
61+
reportAndExit(err)
5862
}
5963

6064
err = iolib.Send(hsMsg1)
6165
if err != nil {
62-
os.Exit(-1)
63-
return
66+
reportAndExit(err)
6467
}
6568

6669
hsMsg2, err := iolib.Recv()
6770
if err != nil {
68-
os.Exit(-1)
69-
return
71+
reportAndExit(err)
7072
}
7173

7274
err = initiator.ProcessHsMsg2(hsMsg2)
7375
if err != nil {
74-
os.Exit(-1)
75-
return
76+
reportAndExit(err)
7677
}
7778

7879
hsMsg3, err := initiator.ProduceHsMsg3()
7980
if err != nil {
80-
os.Exit(-1)
81-
return
81+
reportAndExit(err)
8282
}
8383

8484
err = iolib.Send(hsMsg3)
8585
if err != nil {
86-
os.Exit(-1)
87-
return
86+
reportAndExit(err)
8887
}
8988

9089
// handshake is now over
9190
scanner := bufio.NewScanner(os.Stdin)
91+
fmt.Println("Enter a payload to be sent:")
9292
for scanner.Scan() {
9393
line := scanner.Text()
9494
requestMsg, err := initiator.ProduceTransportMsg([]byte(line))
9595
if err != nil {
96-
os.Exit(-1)
97-
return
96+
reportAndExit(err)
9897
}
9998
err = iolib.Send(requestMsg)
10099
if err != nil {
101-
os.Exit(-1)
102-
return
100+
reportAndExit(err)
103101
}
104102

105103
responseMsg, err := iolib.Recv()
106104
if err != nil {
107-
os.Exit(-1)
108-
return
105+
reportAndExit(err)
109106
}
110107
responsePayload, err := initiator.ProcessTransportMsg(responseMsg)
111108
if err != nil {
112-
os.Exit(-1)
113-
return
109+
reportAndExit(err)
114110
}
115-
fmt.Println(responsePayload)
111+
fmt.Printf("Received: %s\n", string(responsePayload))
112+
fmt.Println("Enter a payload to be sent:")
116113
}
117114

118115
iolib.Close()
119116
if err == nil {
120117
os.Exit(0)
121118
} else {
122-
fmt.Println(err)
123-
os.Exit(1)
119+
reportAndExit(err)
124120
}
125121
}
126122

123+
func reportAndExit(err error) {
124+
fmt.Println(err)
125+
os.Exit(1)
126+
}
127+
127128
func parseKeys(config Config) (privateKey [64]byte, peerPublicKey [32]byte, err error) {
128129
encoding := base64.StdEncoding
129130
privateKeySlice, err := encoding.DecodeString(config.PrivateKey)

dh/implementation/responder/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Build:
1111
```
1212
gradle build
1313
```
14+
The following command explicitly specifies a JDK in case the default one is too old:
15+
```
16+
gradle build -Dorg.gradle.java.home=/opt/homebrew/opt/openjdk
17+
```
1418

1519
Run:
1620
```

dh/implementation/responder/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jar {
2323
attributes 'Main-Class': mainClassName
2424
}
2525
// name of the generated JAR output:
26-
baseName 'dh-gobra'
26+
archiveBaseName.set('dh-gobra')
2727
// to create a fat JAR:
2828
from {
2929
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
@@ -39,6 +39,6 @@ jar {
3939

4040
// set destination for JAR output:
4141
tasks.withType(Jar) {
42-
destinationDir = file("$rootDir")
42+
destinationDirectory = file("$rootDir")
4343
// duplicatesStrategy = DuplicatesStrategy.EXCLUDE
4444
}

dh/implementation/responder/src/main/java/dhgobra/library/Library.java

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
import java.util.Arrays;
55
import java.util.Random;
66
import java.net.*;
7+
import java.nio.ByteBuffer;
78
import java.security.KeyFactory;
89
import java.security.NoSuchAlgorithmException;
10+
import java.security.InvalidAlgorithmParameterException;
911
import java.security.InvalidKeyException;
1012
import java.security.PublicKey;
1113
import java.security.PrivateKey;
14+
import java.security.SecureRandom;
1215
import java.security.Signature;
1316
import java.security.SignatureException;
1417
import java.security.spec.EdECPoint;
@@ -17,9 +20,16 @@
1720
import java.security.spec.NamedParameterSpec;
1821
import java.security.spec.EdECPrivateKeySpec;
1922
import java.security.spec.PKCS8EncodedKeySpec;
20-
import javax.crypto.spec.SecretKeySpec;
2123
import java.security.spec.X509EncodedKeySpec;
2224
import java.io.IOException;
25+
import java.util.Scanner;
26+
import javax.crypto.Cipher;
27+
import javax.crypto.BadPaddingException;
28+
import javax.crypto.IllegalBlockSizeException;
29+
import javax.crypto.NoSuchPaddingException;
30+
import javax.crypto.SecretKey;
31+
import javax.crypto.spec.IvParameterSpec;
32+
import javax.crypto.spec.SecretKeySpec;
2333
// import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
2434
// import org.bouncycastle.crypto.Signer;
2535
// import org.bouncycastle.crypto.signers.Ed25519Signer;
@@ -329,7 +339,7 @@ private boolean longInRange(long value) {
329339
return true;
330340
}
331341

332-
private byte[] uint32ToBytes(long value) {
342+
public byte[] uint32ToBytes(long value) {
333343
if (!longInRange(value)) {
334344
return null;
335345
}
@@ -341,7 +351,7 @@ private byte[] uint32ToBytes(long value) {
341351
};
342352
}
343353

344-
private long bytesToUint32(byte[] data) {
354+
public long bytesToUint32(byte[] data) {
345355
if (data == null || data.length != 4) {
346356
return -1;
347357
}
@@ -359,4 +369,79 @@ public void notMatchY() {
359369
public void success(byte[] sharedSecret) {
360370
System.out.println("Initiator & responder agreed on shared secret " + convertToHex(sharedSecret));
361371
}
372+
373+
private static final String ENCRYPT_ALGO = "ChaCha20-Poly1305";
374+
private static final int NONCE_LEN = 12;
375+
public byte[] encrypt(byte[] plaintext, byte[] key) {
376+
Cipher cipher;
377+
try {
378+
cipher = Cipher.getInstance(ENCRYPT_ALGO);
379+
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
380+
return null;
381+
}
382+
383+
byte[] nonce = new byte[NONCE_LEN];
384+
new SecureRandom().nextBytes(nonce);
385+
386+
// IV, initialization value with nonce
387+
IvParameterSpec iv = new IvParameterSpec(nonce);
388+
389+
SecretKey keyObject = new SecretKeySpec(key, "AES");
390+
try {
391+
cipher.init(Cipher.ENCRYPT_MODE, keyObject, iv);
392+
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
393+
return null;
394+
}
395+
396+
byte[] encryptedText;
397+
try {
398+
encryptedText = cipher.doFinal(plaintext);
399+
} catch (IllegalBlockSizeException | BadPaddingException e) {
400+
return null;
401+
}
402+
403+
// prepend nonce to the encrypted text
404+
byte[] output = ByteBuffer.allocate(encryptedText.length + NONCE_LEN)
405+
.put(nonce)
406+
.put(encryptedText)
407+
.array();
408+
409+
return output;
410+
}
411+
412+
public byte[] decrypt(byte[] ciphertext, byte[] key) {
413+
ByteBuffer bb = ByteBuffer.wrap(ciphertext);
414+
415+
// split ciphertext to get the prepended nonce
416+
byte[] nonce = new byte[NONCE_LEN];
417+
byte[] encryptedText = new byte[ciphertext.length - NONCE_LEN];
418+
bb.get(nonce);
419+
bb.get(encryptedText);
420+
421+
Cipher cipher;
422+
try {
423+
cipher = Cipher.getInstance(ENCRYPT_ALGO);
424+
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
425+
System.out.println(e);
426+
return null;
427+
}
428+
429+
IvParameterSpec iv = new IvParameterSpec(nonce);
430+
431+
SecretKey keyObject = new SecretKeySpec(key, "AES");
432+
try {
433+
cipher.init(Cipher.DECRYPT_MODE, keyObject, iv);
434+
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
435+
System.out.println(e);
436+
return null;
437+
}
438+
439+
// decrypted text
440+
try {
441+
return cipher.doFinal(encryptedText);
442+
} catch (IllegalBlockSizeException | BadPaddingException e) {
443+
System.out.println(e);
444+
return null;
445+
}
446+
}
362447
}

0 commit comments

Comments
 (0)