Skip to content
Snippets Groups Projects
Commit 654633d3 authored by Benjamin Wenger's avatar Benjamin Wenger
Browse files

refactored diffieHelman

parent cff67a56
No related branches found
No related tags found
No related merge requests found
...@@ -13,6 +13,8 @@ package cyclic ...@@ -13,6 +13,8 @@ package cyclic
import ( import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/base64"
"encoding/binary"
"encoding/gob" "encoding/gob"
"encoding/json" "encoding/json"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
...@@ -161,6 +163,13 @@ func (g *Group) GetFingerprint() uint64 { ...@@ -161,6 +163,13 @@ func (g *Group) GetFingerprint() uint64 {
return g.fingerprint return g.fingerprint
} }
func (g *Group) GetFingerprintText() string {
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, g.fingerprint)
fullText := base64.StdEncoding.EncodeToString(buf)
return fullText[:8] + "..."
}
// -------------- Setters -------------- // // -------------- Setters -------------- //
// Set sets x to y in the group and returns x // Set sets x to y in the group and returns x
......
...@@ -305,6 +305,20 @@ func TestGetFingerprint(t *testing.T) { ...@@ -305,6 +305,20 @@ func TestGetFingerprint(t *testing.T) {
} }
} }
// Test group fingerprint getter
func TestGetFingerprintText(t *testing.T) {
p := large.NewInt(1000000010101111111)
g := large.NewInt(5)
grp := NewGroup(p, g)
expected := "ln9lzlk2..."
if grp.GetFingerprintText() != expected {
t.Errorf("GetFingerprintText returned wrong value, expected: %v,"+
" got: %v", expected, grp.GetFingerprintText())
}
}
// Test setting cyclicInt to another from the same group // Test setting cyclicInt to another from the same group
func TestSet(t *testing.T) { func TestSet(t *testing.T) {
p := large.NewInt(1000000010101111111) p := large.NewInt(1000000010101111111)
......
...@@ -9,49 +9,49 @@ ...@@ -9,49 +9,49 @@
package diffieHellman package diffieHellman
import ( import (
"fmt" "github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/crypto/csprng" "gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
) )
// CreateDHKeyPair is a function that receives the generator and prime and const DefaultPrivateKeyLength = 256
// returns a Diffie-Hellman Key pair withing the group
func CreateDHKeyPair(group *cyclic.Group) (*cyclic.Int, *cyclic.Int) {
if !group.GetP().IsPrime() {
jww.FATAL.Panicf("CreateDHKeyPair(): Passed number is not prime")
}
//256 bits
size := 32
csprig := csprng.NewSystemRNG()
k1 := make([]byte, size) // Creates a private key of the passed length in bits in the given group using
// the passed csprng. The length of the key must be within the prime of the
// group. It is recommended to use the "DefaultPrivateKeyLength"
// for most use cases.
// key size must be divisible by 8
func GeneratePrivateKey(size uint, group *cyclic.Group, source csprng.Source) (*cyclic.Int, error) {
_, err := csprig.Read(k1) k1, err := csprng.GenerateInGroup(group.GetPBytes(), int(size/8), source)
if err != nil { if err != nil {
panic(fmt.Sprintf("Key RNG in Diffie Hellman Failed: %s", err.Error())) return nil, errors.Errorf("Failed to generate key: %s", err.Error())
} }
privateKey := group.NewIntFromBytes(k1) privateKey := group.NewIntFromBytes(k1)
return privateKey, nil
}
// Computes a public key for the given private key. The private key must be
// in the group passed
func GeneratePublicKey(myPrivateKey *cyclic.Int, group *cyclic.Group) *cyclic.Int {
publicKey := group.NewInt(1) publicKey := group.NewInt(1)
group.Exp(group.GetGCyclic(), privateKey, publicKey) group.Exp(group.GetGCyclic(), myPrivateKey, publicKey)
return privateKey, publicKey return publicKey
} }
// CreateDHSessionKey takes the prime, the other party's public key and private key // CreateSessionKey takes the prime, the other party's public key and private key
// Function returns a valid session Key within the group // Function returns a valid session Key within the group
// v1.0 still does not include the CheckPublicKeyFeature func GenerateSessionKey(myPrivateKey *cyclic.Int, theirPublicKey *cyclic.Int,
func CreateDHSessionKey(publicKey *cyclic.Int, privateKey *cyclic.Int, group *cyclic.Group) *cyclic.Int {
group *cyclic.Group) (*cyclic.Int, error) {
sessionKey := group.NewInt(1) sessionKey := group.NewInt(1)
group.Exp(publicKey, privateKey, sessionKey) group.Exp(theirPublicKey, myPrivateKey, sessionKey)
return sessionKey, nil return sessionKey
} }
// CheckPublicKey uses the Legendre Symbol calculation to check if a specific public key is valid // CheckPublicKey uses the Legendre Symbol calculation to check if a specific public key is valid
......
...@@ -8,17 +8,17 @@ package diffieHellman ...@@ -8,17 +8,17 @@ package diffieHellman
import ( import (
"encoding/hex" "encoding/hex"
"gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/large" "gitlab.com/elixxir/crypto/large"
"testing" "testing"
) )
// TestDHKX tests both the CreateDHKeyPair & CreateDHSessionKey // Tests that private key generates a valid private Key and errors and edge
// This function checks if values are within the expected group and if session keys between two parties match // cases are handled correctly
func TestDHKX(t *testing.T) { func TestGeneratePrivateKey(t *testing.T) {
tests := 3 const numGenerations = 50
pass := 0
primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
...@@ -36,48 +36,69 @@ func TestDHKX(t *testing.T) { ...@@ -36,48 +36,69 @@ func TestDHKX(t *testing.T) {
g := large.NewInt(2) g := large.NewInt(2)
grp := cyclic.NewGroup(p, g) grp := cyclic.NewGroup(p, g)
// Creation of two different DH Key Pairs with valid parameters rng := csprng.NewSystemRNG()
privKey, pubKey := CreateDHKeyPair(grp)
privKey2, pubKey2 := CreateDHKeyPair(grp) // create a private key and check it is the correct length with the default size
// do this over and over becasue the size can generate smaller
//Creation of 2 DH Session Keys maxSize := 0
sessionKey1, _ := CreateDHSessionKey(pubKey, privKey2, grp)
sessionKey2, _ := CreateDHSessionKey(pubKey2, privKey, grp)
// Comparison of Two Session Keys (0 means they are equal)
if sessionKey1.Cmp(sessionKey2) != 0 {
t.Errorf("TestDHKX(): Error in CreateDHSessionKey() -> Session Keys do not match!")
} else {
pass++
}
println("TestDHKX():", pass, "out of", tests, "tests passed.") for i := 0; i < numGenerations; i++ {
privKey, _ := GeneratePrivateKey(DefaultPrivateKeyLength, grp, rng)
if privKey.BitLen() > maxSize {
maxSize = privKey.BitLen()
}
} }
// Catch calls recover to catch the panic thrown in the GenerateSharedKey() test functions if maxSize != DefaultPrivateKeyLength {
func Catch(fn string, t *testing.T) { t.Errorf("Generated Private Keys never met correct length: "+
if r := recover(); r != nil { "Expected :%v, Received: %v", DefaultPrivateKeyLength, maxSize)
println("Good news! Panic was caught!", fn, " Had to trigger recover in", r)
} else {
t.Errorf("No panic was caught and it was expected to!")
} }
} }
// TestCreateDHKeyPair checks if panic is triggered when passing a number that is not a prime //tests public keys are generated correctly
func TestCreateDHKeyPair(t *testing.T) { func TestGeneratePublicKey(t *testing.T) {
const numTests = 50
p := large.NewInt(4) primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
p := large.NewInt(1)
p.SetString(primeString, 16)
g := large.NewInt(2) g := large.NewInt(2)
grp := cyclic.NewGroup(p, g) grp := cyclic.NewGroup(p, g)
defer Catch("TestCreateDHKeyPair():", t) rng := csprng.NewSystemRNG()
CreateDHKeyPair(grp)
}
func TestCheckPublicKey(t *testing.T) { for i := 0; i < numTests; i++ {
//create public key
privKey, _ := GeneratePrivateKey(DefaultPrivateKeyLength, grp, rng)
publicKey := GeneratePublicKey(privKey, grp)
tests := 3 //create public key manually
pass := 0 publicKeyExpected := grp.NewInt(1)
grp.Exp(grp.GetGCyclic(), privKey, publicKeyExpected)
if publicKey.Cmp(publicKeyExpected) != 0 {
t.Errorf("Public key generated on attempt %v incorrect;"+
"\n\tExpected: %s \n\tRecieved: %s \n\tPrivate key: %s", i,
publicKeyExpected.TextVerbose(16, 0),
publicKey.TextVerbose(16, 0),
privKey.TextVerbose(16, 0))
}
}
}
//tests Session keys are generated correctly
func TestGenerateSessionKey(t *testing.T) {
const numTests = 50
primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
...@@ -95,53 +116,31 @@ func TestCheckPublicKey(t *testing.T) { ...@@ -95,53 +116,31 @@ func TestCheckPublicKey(t *testing.T) {
g := large.NewInt(2) g := large.NewInt(2)
grp := cyclic.NewGroup(p, g) grp := cyclic.NewGroup(p, g)
// Creation of a DH Key Pair with valid parameters rng := csprng.NewSystemRNG()
_, pubKey := CreateDHKeyPair(grp)
// Random 2048 bit number that is not a quadratic residue for i := 0; i < numTests; i++ {
randomNum := "27a0ed88dd37d9d9c041bd31500e239ac050b618502a64e7f703dba20390" + //create session key
"36638ca17c7bca05973b9ab5057bc535bebe6b98afee010785a32ae06184dcfe12123" + privKey, _ := GeneratePrivateKey(DefaultPrivateKeyLength, grp, rng)
"5ea901d154d317480f381ff1fc49867d22d3c8f1f9e83e6d19f7554401fc32148b3d0" + publicKey := GeneratePublicKey(privKey, grp)
"40c57c7d7cc08445776bd8ffc0d62016bf82708985c97b873d0f81a87072d6bfbbbb0" + session := GenerateSessionKey(privKey, publicKey, grp)
"1e31679386641720c444c00a64720ffe3649d2b1fdf458acf65d0e695d6a293c34c70" +
"e84d5e5a66d710475b6baea78df56e0c5ee735d496c1e3bc7f5fa95b4cd1b1bd849f9" +
"487411805e7c9a1503735ba3d7d71ffb8f51e8530abb335e9c315e56677d30a4f7144" +
"0a34a6954938d29fd24a72aae3d4a0c2873ed4"
a, _ := hex.DecodeString(randomNum) //create public key manually
x := grp.NewIntFromBytes(a) sessionExpected := grp.NewInt(1)
grp.Exp(publicKey, privKey, sessionExpected)
rightSymbol := CheckPublicKey(grp, pubKey) if session.Cmp(sessionExpected) != 0 {
fakeSymbol := CheckPublicKey(grp, grp.NewInt(1)) t.Errorf("Session key generated on attempt %v incorrect;"+
falseSymbol := CheckPublicKey(grp, x) "\n\tExpected: %s \n\tRecieved: %s \n\tPrivate key: %s", i,
sessionExpected.TextVerbose(16, 0),
if rightSymbol { session.TextVerbose(16, 0),
pass++ privKey.TextVerbose(16, 0))
} else {
t.Errorf("TestCheckPublicKey(): Public Key is supposed to be valid!")
} }
if fakeSymbol {
t.Errorf("TestCheckPublicKey(): 1 should not be valid input!")
} else {
pass++
}
if falseSymbol {
t.Errorf("TestCheckPublicKey(): Random value should not be valid!")
} else {
pass++
} }
println("TestCheckPublicKey():", pass, "out of", tests, "tests passed.")
} }
/* // Verifies that checkPublic key returns correct responses on valid and
// TestDHNodeKeys tests if the hardcoded keys are valid // invalid inputs
func TestDHNodeKeys(t *testing.T) { func TestCheckPublicKey(t *testing.T) {
tests := 3
pass := 0
primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
...@@ -157,88 +156,47 @@ func TestDHNodeKeys(t *testing.T) { ...@@ -157,88 +156,47 @@ func TestDHNodeKeys(t *testing.T) {
p := large.NewInt(1) p := large.NewInt(1)
p.SetString(primeString, 16) p.SetString(primeString, 16)
g := large.NewInt(2) g := large.NewInt(2)
q := large.NewInt(3) grp := cyclic.NewGroup(p, g)
grp := cyclic.NewGroup(p, g, q)
testGroup := &grp
// This is a map key(string) -> value (hex string)
// To convert the contents to byte, one should do: res, _ := hex.DecodeString(nodeDHKeys["key"])
nodeDHPrivateKeys := map[string]string{
"1": "4676d728cf9515f474170042f7ea2da582900bcbf46e921b7a5a9139e36c94ab",
"2": "9b9e9ba8826594edba543a08cff2805b56c618fecce7a186ada654d9a7a49ba9",
"3": "137f66dc73ad0a2fafc2892fcd75fa578d1dda9a17268f5cd9fc778d85027ba4",
}
nodeDHPublicKeys := map[string]string{
"1": "610867349dd0abad45c94a728fff49ffc0187723599c25c09805b14d43f6fc2d" +
"de24bda8a38997ee11656bbf73c27098b51672fb212759474309edac7e877c38fcc5300cdaa0" +
"6080154a140f80724e82f55f6388cb101bb4bd4c68930fb2493185508bda03608503dfbed434" +
"632993df4ff4cbecc11891d5df1c3699b042bbd027d385f253ca7299869acc4792586f5c2d37" +
"850afcbda08a8fe467d86729c30922a7983727bdf71bf0c9eed541e686e8b1a1ae1ca3f26aee" +
"d42d881f28835e1b68cd89cbb35c5ad03f5fe4b6bd2fbaffdb284ac34ae65ecba4375701dfc9" +
"a5d7cccf0fa1715b83502f638d076875ead5c7feac64095b1967cf9b89e6ac295f56",
"2": "4dd10b87778ae0969e6c1fe1af002ec78f2ff676b8ab5f6ebf3e4b4228e78609" +
"4d22f4c43cda66888b5d6b32c4cd44c3db33bc74078a0363a4dfe6f6d72da5ab312e7da3658" +
"b31f1488f8eb5aaa002f471309cd8e2ca05ad10be3d2204b5c68e1bc46e3554737f295d739b" +
"caa5f3316847fcdae513150d1f84a69b8ef92fc0bb540ef1bc90b6100170ac0bd3f2c6c9863" +
"532c0d4f302dae33bb8c8f8b8d9fce1264a5e60ac2beaf3f0d415cfd68aeca3822e6ce3d5e7" +
"e3b3ee477e272767cdd69eb6268cd696b79826256e25b7e5a3bc79dcd1f86f843b4d45d63e0" +
"4ea078f5ddf4a22dc43503660387a94d60020e05d1e7f1e9c032cad58f2d7408755f49942",
"3": "fa2f3be8b4d5f748ed8332193db18045b781acfe165e2a8a6924d6fc514f29d6" +
"cdf49b917b3b67985294c31990f9e5f402e0ff471a4eee44a7910a42a89d11cd832043327ac" +
"62c3bf9e55ecce5ca5b5d53d0d442b94c86797a30fefc6692627f756bc96c50d131355dec50" +
"3af5df8b113f280fc24ff2591b6c062b009312345432f8c201694379e04909cedd2ee5b41b7" +
"a5158ef5804679859f6fdf5a4be7defaaa4cdc0b5b66fc98cd85d19b9e53f79d513a9c0654a" +
"438f2bdee2b22022eda1cc80930b65ac381ca519afa6646df357ca223aa63ffbadd3bc6476e" +
"b88b482129d1167c7787662abf0a5bf434e934039e681092916a12d7be295482718f748af",
}
pk1, _ := hex.DecodeString(nodeDHPublicKeys["publicKey1"]) rng := csprng.NewSystemRNG()
pk2, _ := hex.DecodeString(nodeDHPublicKeys["publicKey2"])
pk3, _ := hex.DecodeString(nodeDHPublicKeys["publicKey3"])
sk1, _ := hex.DecodeString(nodeDHPrivateKeys["1"]) // Creation of a DH Key Pair with valid parameters
sk2, _ := hex.DecodeString(nodeDHPrivateKeys["2"]) privKey, _ := GeneratePrivateKey(DefaultPrivateKeyLength, grp, rng)
sk3, _ := hex.DecodeString(nodeDHPrivateKeys["3"]) publicKey := GeneratePublicKey(privKey, grp)
// Keys between Node 1 & 2 // Random 2048 bit number that is not a quadratic residue
k12, _ := CreateDHSessionKey(grp.NewIntFromBytes(pk2), grp.NewIntFromBytes(sk1), testGroup) randomNum := "27a0ed88dd37d9d9c041bd31500e239ac050b618502a64e7f703dba20390" +
k21, _ := CreateDHSessionKey(grp.NewIntFromBytes(pk1), grp.NewIntFromBytes(sk2), testGroup) "36638ca17c7bca05973b9ab5057bc535bebe6b98afee010785a32ae06184dcfe12123" +
"5ea901d154d317480f381ff1fc49867d22d3c8f1f9e83e6d19f7554401fc32148b3d0" +
"40c57c7d7cc08445776bd8ffc0d62016bf82708985c97b873d0f81a87072d6bfbbbb0" +
"1e31679386641720c444c00a64720ffe3649d2b1fdf458acf65d0e695d6a293c34c70" +
"e84d5e5a66d710475b6baea78df56e0c5ee735d496c1e3bc7f5fa95b4cd1b1bd849f9" +
"487411805e7c9a1503735ba3d7d71ffb8f51e8530abb335e9c315e56677d30a4f7144" +
"0a34a6954938d29fd24a72aae3d4a0c2873ed4"
// Keys between Node 1 & 3 a, _ := hex.DecodeString(randomNum)
k13, _ := CreateDHSessionKey(grp.NewIntFromBytes(pk1), grp.NewIntFromBytes(sk3), testGroup) x := grp.NewIntFromBytes(a)
k31, _ := CreateDHSessionKey(grp.NewIntFromBytes(pk3), grp.NewIntFromBytes(sk1), testGroup)
// Keys between Node 2 & 3 rightSymbol := CheckPublicKey(grp, publicKey)
k23, _ := CreateDHSessionKey(grp.NewIntFromBytes(pk2), grp.NewIntFromBytes(sk3), testGroup) fakeSymbol := CheckPublicKey(grp, grp.NewInt(1))
k32, _ := CreateDHSessionKey(grp.NewIntFromBytes(pk3), grp.NewIntFromBytes(sk2), testGroup) falseSymbol := CheckPublicKey(grp, x)
if k12.Cmp(k21) != 0 { if !rightSymbol {
t.Errorf("Keys between Node 1 & 2 do not match!") t.Errorf("Public Key is supposed to be valid!")
} else {
pass++
} }
if k13.Cmp(k31) != 0 { if fakeSymbol {
t.Errorf("Keys between Node 1 & 3 do not match!") t.Errorf("1 should not be valid input!")
} else {
pass++
} }
if k23.Cmp(k32) != 0 { if falseSymbol {
t.Errorf("Keys between Node 2 & 3 do not match!") t.Errorf("Random value should not be valid!")
} else {
pass++
} }
println("TestDHNodeKeys():", pass, "out of", tests, "tests passed.") }
}*/
//benchmarks session key creation
func BenchmarkCreateDHSessionKey(b *testing.B) { func BenchmarkCreateDHSessionKey(b *testing.B) {
primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + primeString := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
...@@ -258,20 +216,17 @@ func BenchmarkCreateDHSessionKey(b *testing.B) { ...@@ -258,20 +216,17 @@ func BenchmarkCreateDHSessionKey(b *testing.B) {
pubkeys := make([]*cyclic.Int, b.N) pubkeys := make([]*cyclic.Int, b.N)
privkeys := make([]*cyclic.Int, b.N) privkeys := make([]*cyclic.Int, b.N)
for i := 0; i < b.N; i++ { rng := csprng.NewSystemRNG()
for i := 0; i < b.N; i++ {
// Creation of two different DH Key Pairs with valid parameters // Creation of two different DH Key Pairs with valid parameters
_, pubKey := CreateDHKeyPair(grp) privkeys[i], _ = GeneratePrivateKey(DefaultPrivateKeyLength, grp, rng)
privKey, _ := CreateDHKeyPair(grp) tmpPrivKey, _ := GeneratePrivateKey(DefaultPrivateKeyLength, grp, rng)
pubkeys[i] = GeneratePublicKey(tmpPrivKey, grp)
pubkeys[i] = pubKey
privkeys[i] = privKey
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
GenerateSessionKey(pubkeys[i], privkeys[i], grp)
CreateDHSessionKey(pubkeys[i], privkeys[i], grp)
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment