doubleratchet/default_crypto_test.go

223 lines
6.0 KiB
Go

package doubleratchet
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
func TestDhPair(t *testing.T) {
// Arrange.
p := dhPair{
privateKey: []byte{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
publicKey: []byte{6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
}
// Act.
var (
privKey = p.PrivateKey()
pubKey = p.PublicKey()
)
// Assert.
require.Equal(t, p.privateKey, privKey)
require.Equal(t, p.publicKey, pubKey)
require.Equal(t, fmt.Sprintf(`{privateKey: %s publicKey: %s}`, p.PrivateKey(), p.PublicKey()), p.String())
}
func TestDefaultCrypto_GenerateDH_Basic(t *testing.T) {
// Arrange.
c := DefaultCrypto{}
// Act.
pair, err := c.GenerateDH()
// Assert.
require.Nil(t, err)
require.EqualValues(t, 0, pair.PrivateKey()[0]&7)
require.EqualValues(t, 0, pair.PrivateKey()[31]&128)
require.EqualValues(t, 64, pair.PrivateKey()[31]&64)
require.NotEqual(t, nil, pair.PrivateKey())
require.NotEqual(t, nil, pair.PublicKey())
require.Len(t, pair.PrivateKey(), 32)
require.Len(t, pair.PublicKey(), 32)
require.NotEqual(t, pair.PublicKey(), pair.PrivateKey())
}
func TestDefaultCrypto_GenerateDH_DifferentKeysEveryTime(t *testing.T) {
// Arrange.
var (
c = DefaultCrypto{}
keys = make(map[string]bool)
)
for i := 0; i < 10; i++ {
t.Run("", func(t *testing.T) {
// Act.
pair, err := c.GenerateDH()
// Assert.
require.Nil(t, err)
privateKeyString := fmt.Sprintf("%x", pair.PrivateKey())
publicKeyString := fmt.Sprintf("%x", pair.PublicKey())
require.False(t, keys[privateKeyString])
require.False(t, keys[publicKeyString])
// Preserve.
keys[privateKeyString] = true
keys[publicKeyString] = true
})
}
}
func TestDefaultCrypto_DH(t *testing.T) {
// Arrange.
c := DefaultCrypto{}
// Act.
var (
alicePair, err1 = c.GenerateDH()
bobPair, err2 = c.GenerateDH()
aliceSK, err3 = c.DH(alicePair, bobPair.PublicKey())
bobSK, err4 = c.DH(bobPair, alicePair.PublicKey())
)
// Assert.
require.Nil(t, err1)
require.Nil(t, err2)
require.Nil(t, err3)
require.Nil(t, err4)
require.NotEqual(t, nil, aliceSK)
require.Equal(t, aliceSK, bobSK)
}
func TestDefaultCrypto_KdfRK(t *testing.T) {
// Arrange.
c := DefaultCrypto{}
// Act.
// TODO: Test hk.
newRK, newCK, _ := c.KdfRK(
[]byte{0xeb, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40},
[]byte{0x9c, 0x1e, 0x68, 0xab, 0x9d, 0x45, 0xf5, 0x82, 0x35, 0xc4, 0x2, 0xa8, 0x82, 0xa1, 0x46, 0x55, 0x35, 0x41, 0xf1, 0x9d, 0x87, 0x2b, 0x59, 0x24, 0x39, 0x3b, 0x91, 0xf7, 0xda, 0x46, 0x56, 0xf},
)
// Assert.
require.NotEqual(t, nil, newRK)
require.NotEqual(t, nil, newCK)
require.Len(t, newRK, 32)
require.Len(t, newCK, 32)
require.NotEqual(t, newRK, newCK)
}
func TestDefaultCrypto_KdfCK(t *testing.T) {
// Arrange.
c := DefaultCrypto{}
// Act.
newCK, mk := c.KdfCK([]byte{0xeb, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40})
// Assert.
require.NotEqual(t, nil, newCK)
require.NotEqual(t, nil, mk)
require.Len(t, newCK, 32)
require.Len(t, mk, 32)
require.NotEqual(t, mk, newCK)
}
func TestDefaultCrypto_deriveEncKeys(t *testing.T) {
// Arrange.
c := DefaultCrypto{}
// Act.
encKey, authKey, iv := c.deriveEncKeys([]byte{0xeb, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40})
// Assert.
require.Len(t, encKey, 32)
require.Len(t, authKey, 32)
require.Len(t, iv, 16)
require.NotEqual(t, nil, encKey)
require.NotEqual(t, nil, authKey)
require.NotContains(t, encKey, iv)
require.NotContains(t, authKey, iv)
require.NotEqual(t, encKey, authKey)
}
func TestDefaultCrypto_computeSignature(t *testing.T) {
// Arrange.
var (
c = DefaultCrypto{}
ciphertext = []byte{13, 250, 114, 78}
)
// Act.
signature := c.computeSignature(
[]byte{0xeb, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40},
ciphertext,
nil,
)
// Assert.
require.Len(t, signature, 32)
require.NotEqual(t, nil, signature)
}
func TestDefaultCrypto_EncryptDecrypt(t *testing.T) {
// Arrange.
var (
c = DefaultCrypto{}
msg = []byte("1337")
mk = []byte{0xeb, 0x8, 0x10, 0x7c, 0x33, 0x54, 0x0, 0x20, 0xe9, 0x4f, 0x6c, 0x84, 0xe4, 0x39, 0x50, 0x5a, 0x2f, 0x60, 0xbe, 0x81, 0xa, 0x78, 0x8b, 0xeb, 0x1e, 0x2c, 0x9, 0x8d, 0x4b, 0x4d, 0xc1, 0x40}
)
t.Run("no associated data", func(t *testing.T) {
// Act.
ciphertext, err := c.Encrypt(mk, msg, nil)
require.Nil(t, err)
plaintext, err := c.Decrypt(mk, ciphertext, nil)
require.Nil(t, err)
// Assert.
require.Len(t, ciphertext, 16+len(msg)+32) // iv + plaintext length + signature
require.Equal(t, msg, plaintext)
})
t.Run("same associated data", func(t *testing.T) {
// Act.
ciphertext, err := c.Encrypt(mk, msg, []byte("any secret"))
require.Nil(t, err)
plaintext, err := c.Decrypt(mk, ciphertext, []byte("any secret"))
require.Nil(t, err)
// Assert.
require.Len(t, ciphertext, 32+16+len(msg)) // signature + iv + plaintext length
require.Equal(t, msg, plaintext)
})
t.Run("different associated data", func(t *testing.T) {
// Act.
ciphertext, err := c.Encrypt(mk, msg, []byte("not secret at all"))
require.Nil(t, err)
_, err = c.Decrypt(mk, ciphertext, []byte("any secret"))
require.EqualError(t, err, "invalid signature")
})
t.Run("malformed signature", func(t *testing.T) {
// Act.
ciphertext, err := c.Encrypt(mk, msg, nil)
require.Nil(t, err)
ciphertext[len(ciphertext)-1] ^= 57 // Inverse the last byte in the signature.
_, err = c.Decrypt(mk, ciphertext, nil)
// Assert.
require.EqualError(t, err, "invalid signature")
})
}