github.com/status-im/status-go@v1.1.0/protocol/encryption/x3dh_test.go (about) 1 package encryption 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 "github.com/status-im/status-go/eth-node/crypto" 10 "github.com/status-im/status-go/eth-node/crypto/ecies" 11 ) 12 13 const ( 14 alicePrivateKey = "00000000000000000000000000000000" 15 aliceEphemeralKey = "11111111111111111111111111111111" 16 bobPrivateKey = "22222222222222222222222222222222" 17 bobSignedPreKey = "33333333333333333333333333333333" 18 ) 19 20 var sharedKey = []byte{0xa4, 0xe9, 0x23, 0xd0, 0xaf, 0x8f, 0xe7, 0x8a, 0x5, 0x63, 0x63, 0xbe, 0x20, 0xe7, 0x1c, 0xa, 0x58, 0xe5, 0x69, 0xea, 0x8f, 0xc1, 0xf7, 0x92, 0x89, 0xec, 0xa1, 0xd, 0x9f, 0x68, 0x13, 0x3a} 21 22 func bobBundle() (*Bundle, error) { 23 privateKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) 24 if err != nil { 25 return nil, err 26 } 27 28 signedPreKey, err := crypto.ToECDSA([]byte(bobSignedPreKey)) 29 if err != nil { 30 return nil, err 31 } 32 33 compressedPreKey := crypto.CompressPubkey(&signedPreKey.PublicKey) 34 35 signature, err := crypto.Sign(crypto.Keccak256(compressedPreKey), privateKey) 36 if err != nil { 37 return nil, err 38 } 39 40 signedPreKeys := make(map[string]*SignedPreKey) 41 signedPreKeys[bobInstallationID] = &SignedPreKey{SignedPreKey: compressedPreKey} 42 43 bundle := Bundle{ 44 Identity: crypto.CompressPubkey(&privateKey.PublicKey), 45 SignedPreKeys: signedPreKeys, 46 Signature: signature, 47 } 48 49 return &bundle, nil 50 } 51 52 func TestNewBundleContainer(t *testing.T) { 53 privateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) 54 require.NoError(t, err, "Private key should be generated without errors") 55 56 bundleContainer, err := NewBundleContainer(privateKey, bobInstallationID) 57 require.NoError(t, err, "Bundle container should be created successfully") 58 59 err = SignBundle(privateKey, bundleContainer) 60 require.NoError(t, err, "Bundle container should be signed successfully") 61 62 require.NoError(t, err, "Bundle container should be created successfully") 63 64 bundle := bundleContainer.Bundle 65 require.NotNil(t, bundle, "Bundle should be generated without errors") 66 67 signatureMaterial := append([]byte(bobInstallationID), bundle.GetSignedPreKeys()[bobInstallationID].GetSignedPreKey()...) 68 signatureMaterial = append(signatureMaterial, []byte("0")...) 69 signatureMaterial = append(signatureMaterial, []byte(fmt.Sprint(bundle.GetTimestamp()))...) 70 recoveredPublicKey, err := crypto.SigToPub( 71 crypto.Keccak256(signatureMaterial), 72 bundle.Signature, 73 ) 74 75 require.NoError(t, err, "Public key should be recovered from the bundle successfully") 76 77 require.Equal( 78 t, 79 privateKey.PublicKey, 80 *recoveredPublicKey, 81 "The correct public key should be recovered", 82 ) 83 } 84 85 func TestSignBundle(t *testing.T) { 86 privateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) 87 require.NoError(t, err, "Private key should be generated without errors") 88 89 bundleContainer1, err := NewBundleContainer(privateKey, "1") 90 require.NoError(t, err, "Bundle container should be created successfully") 91 92 bundle1 := bundleContainer1.Bundle 93 require.NotNil(t, bundle1, "Bundle should be generated without errors") 94 95 // We add a signed pre key 96 signedPreKeys := bundle1.GetSignedPreKeys() 97 signedPreKeys["2"] = &SignedPreKey{SignedPreKey: []byte("key")} 98 99 err = SignBundle(privateKey, bundleContainer1) 100 require.NoError(t, err) 101 102 signatureMaterial := append([]byte("1"), bundle1.GetSignedPreKeys()["1"].GetSignedPreKey()...) 103 signatureMaterial = append(signatureMaterial, []byte("0")...) 104 signatureMaterial = append(signatureMaterial, []byte("2")...) 105 signatureMaterial = append(signatureMaterial, []byte("key")...) 106 signatureMaterial = append(signatureMaterial, []byte("0")...) 107 signatureMaterial = append(signatureMaterial, []byte(fmt.Sprint(bundle1.GetTimestamp()))...) 108 109 recoveredPublicKey, err := crypto.SigToPub( 110 crypto.Keccak256(signatureMaterial), 111 bundleContainer1.GetBundle().Signature, 112 ) 113 114 require.NoError(t, err, "Public key should be recovered from the bundle successfully") 115 116 require.Equal( 117 t, 118 privateKey.PublicKey, 119 *recoveredPublicKey, 120 "The correct public key should be recovered", 121 ) 122 } 123 124 func TestExtractIdentity(t *testing.T) { 125 privateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) 126 require.NoError(t, err, "Private key should be generated without errors") 127 128 bundleContainer, err := NewBundleContainer(privateKey, "1") 129 require.NoError(t, err, "Bundle container should be created successfully") 130 131 err = SignBundle(privateKey, bundleContainer) 132 require.NoError(t, err, "Bundle container should be signed successfully") 133 134 bundle := bundleContainer.Bundle 135 require.NotNil(t, bundle, "Bundle should be generated without errors") 136 137 recoveredPublicKey, err := ExtractIdentity(bundle) 138 139 require.NoError(t, err, "Public key should be recovered from the bundle successfully") 140 141 require.Equal( 142 t, 143 privateKey.PublicKey, 144 *recoveredPublicKey, 145 "The correct public key should be recovered", 146 ) 147 } 148 149 // Alice wants to send a message to Bob 150 func TestX3dhActive(t *testing.T) { 151 bobIdentityKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) 152 require.NoError(t, err, "Bundle identity key should be generated without errors") 153 154 bobSignedPreKey, err := crypto.ToECDSA([]byte(bobSignedPreKey)) 155 require.NoError(t, err, "Bundle signed pre key should be generated without errors") 156 157 aliceIdentityKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) 158 require.NoError(t, err, "Private key should be generated without errors") 159 160 aliceEphemeralKey, err := crypto.ToECDSA([]byte(aliceEphemeralKey)) 161 require.NoError(t, err, "Ephemeral key should be generated without errors") 162 163 x3dh, err := x3dhActive( 164 ecies.ImportECDSA(aliceIdentityKey), 165 ecies.ImportECDSAPublic(&bobSignedPreKey.PublicKey), 166 ecies.ImportECDSA(aliceEphemeralKey), 167 ecies.ImportECDSAPublic(&bobIdentityKey.PublicKey), 168 ) 169 require.NoError(t, err, "Shared key should be generated without errors") 170 require.Equal(t, sharedKey, x3dh, "Should generate the correct key") 171 } 172 173 // Bob receives a message from Alice 174 func TestPerformPassiveX3DH(t *testing.T) { 175 alicePrivateKey, err := crypto.ToECDSA([]byte(alicePrivateKey)) 176 require.NoError(t, err, "Private key should be generated without errors") 177 178 bobSignedPreKey, err := crypto.ToECDSA([]byte(bobSignedPreKey)) 179 require.NoError(t, err, "Private key should be generated without errors") 180 181 aliceEphemeralKey, err := crypto.ToECDSA([]byte(aliceEphemeralKey)) 182 require.NoError(t, err, "Ephemeral key should be generated without errors") 183 184 bobPrivateKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) 185 require.NoError(t, err, "Private key should be generated without errors") 186 187 x3dh, err := PerformPassiveX3DH( 188 &alicePrivateKey.PublicKey, 189 bobSignedPreKey, 190 &aliceEphemeralKey.PublicKey, 191 bobPrivateKey, 192 ) 193 require.NoError(t, err, "Shared key should be generated without errors") 194 require.Equal(t, sharedKey, x3dh, "Should generate the correct key") 195 } 196 197 func TestPerformActiveX3DH(t *testing.T) { 198 bundle, err := bobBundle() 199 require.NoError(t, err, "Test bundle should be generated without errors") 200 201 privateKey, err := crypto.ToECDSA([]byte(bobPrivateKey)) 202 require.NoError(t, err, "Private key should be imported without errors") 203 204 signedPreKey := bundle.GetSignedPreKeys()[bobInstallationID].GetSignedPreKey() 205 206 actualSharedSecret, actualEphemeralKey, err := PerformActiveX3DH(bundle.GetIdentity(), signedPreKey, privateKey) 207 require.NoError(t, err, "No error should be reported") 208 require.NotNil(t, actualEphemeralKey, "An ephemeral key-pair should be generated") 209 require.NotNil(t, actualSharedSecret, "A shared key should be generated") 210 }