blob: 6959413fc2fcc30a091d185af7145f3bff0ec292 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ibe
import (
"bytes"
"crypto/rand"
"reflect"
"testing"
)
type SetupFunc func() (Master, error)
func TestHashVal(t *testing.T) {
var (
prefix0 = [1]byte{0x00}
prefix1 = [1]byte{0x01}
msg0 = []byte("message 0")
msg1 = []byte("message 1")
)
// Hashes of distinct messages (with the same prefix) should be different
if bytes.Equal(hashval(prefix0, msg0)[:], hashval(prefix0, msg1)[:]) {
t.Errorf("Hashing two distinct values produced same output")
}
// Hashes of identical messages with different prefixes should be different
if bytes.Equal(hashval(prefix0, msg0)[:], hashval(prefix1, msg1)[:]) {
t.Errorf("Hashing two messages with different prefixes produced same output")
}
}
func testBBCorrectness(t *testing.T, setup SetupFunc) {
master, err := setup()
if err != nil {
t.Fatal(err)
}
const (
alice = "alice"
bob = "bob"
)
// Extract
aliceSK, err := master.Extract(alice)
if err != nil {
t.Fatal(err)
}
aliceSK2, err := master.Extract(alice)
if err != nil {
t.Fatal(err)
} else if reflect.DeepEqual(aliceSK, aliceSK2) {
t.Fatal("Two Extract operations yielded the same PrivateKey!")
}
bobSK, err := master.Extract(bob)
if err != nil {
t.Fatal(err)
}
// Encrypt
m := []byte("AThirtyTwoBytePieceOfTextThisIs!")
overhead := master.Params().CiphertextOverhead()
C := make([]byte, len(m)+overhead)
C2 := make([]byte, len(m)+overhead)
if err := master.Params().Encrypt(alice, m, C); err != nil {
t.Fatal(err)
}
if err := master.Params().Encrypt(alice, m, C2); err != nil {
t.Fatal(err)
}
if bytes.Equal(C, C2) {
t.Errorf("Repeated encryptions of the identical plaintext should not produce identical ciphertext")
}
// Decrypt
decrypt := func(sk PrivateKey) ([]byte, error) {
ret := make([]byte, len(C)-overhead)
if err := sk.Decrypt(C, ret); err != nil {
return nil, err
}
return ret, nil
}
if decrypted, err := decrypt(aliceSK); err != nil || !bytes.Equal(decrypted, m) {
t.Errorf("Got (%v, %v), want (%v, nil)", decrypted, err, m[:])
}
if decrypted, err := decrypt(aliceSK2); err != nil || !bytes.Equal(decrypted, m) {
t.Errorf("Got (%v, %v), want (%v, nil)", decrypted, err, m[:])
}
if _, err := decrypt(bobSK); err == nil {
t.Errorf("Decrypted message with a different PrivateKey")
}
}
func TestBB1Correctness(t *testing.T) { testBBCorrectness(t, SetupBB1) }
func TestBB2Correctness(t *testing.T) { testBBCorrectness(t, SetupBB2) }
// Applying the Fujisaki-Okamoto transformation to the BB1 IBE
// scheme yields a CCA2-secure encryption scheme. Since CCA2-security
// implies non-malleability, we verify that a tampered ciphertext
// does not properly decrypt in this test case.
func testBBNonMalleability(t *testing.T, setup SetupFunc) {
master, err := setup()
if err != nil {
t.Fatal(err)
}
const alice = "alice"
aliceSK, err := master.Extract(alice)
if err != nil {
t.Fatal(err)
}
m := []byte("01234567899876543210123456789012")
overhead := master.Params().CiphertextOverhead()
C := make([]byte, len(m)+overhead)
if err := master.Params().Encrypt(alice, m, C); err != nil {
t.Fatal(err)
}
out := make([]byte, len(C)-overhead)
// Test that an untampered C can be decrypted successfully.
if err := aliceSK.Decrypt(C, out); err != nil || !bytes.Equal(out, m) {
t.Fatal(err)
}
// Test that a tampered C cannot be decrypted successfully.
C[0] = C[0] ^ byte(1)
if err := aliceSK.Decrypt(C, out); err == nil {
t.Fatalf("successfully decrypted a tampered ciphetext: %v", err)
}
}
func TestBB1NonMalleability(t *testing.T) { testBBNonMalleability(t, SetupBB1) }
func TestBB2NonMalleability(t *testing.T) { testBBNonMalleability(t, SetupBB2) }
func testMarshaling(t *testing.T, setup SetupFunc) {
master, err := setup()
if err != nil {
t.Fatal(err)
}
bbParams := master.Params()
bbSK, err := master.Extract("alice")
if err != nil {
t.Fatal(err)
}
pbytes, err := MarshalParams(bbParams)
if err != nil {
t.Fatal(err)
}
skbytes, err := MarshalPrivateKey(bbSK)
if err != nil {
t.Fatal(err)
}
m := []byte("01234567899876543210123456789012")
overhead := bbParams.CiphertextOverhead()
var (
C1 = make([]byte, len(m)+overhead)
C2 = make([]byte, len(m)+overhead)
m1 = make([]byte, len(m))
m2 = make([]byte, len(m))
)
// Encrypt with the original params, decrypt with the unmarshaled key.
if err := bbParams.Encrypt("alice", m, C1); err != nil {
t.Error(err)
} else if sk, err := UnmarshalPrivateKey(bbParams, skbytes); err != nil {
t.Error(err)
} else if err := sk.Decrypt(C1, m2); err != nil {
t.Error(err)
} else if !bytes.Equal(m, m2) {
t.Errorf("Got %q, want %q", m, m2)
}
// Encrypt with the unmarshaled params, decrypt with the original key.
if p, err := UnmarshalParams(pbytes); err != nil {
t.Error(err)
} else if err := p.Encrypt("alice", m, C2); err != nil {
t.Error(err)
} else if err := bbSK.Decrypt(C2, m1); err != nil {
t.Error(err)
} else if !bytes.Equal(m, m1) {
t.Errorf("Got %q, want %q", m, m1)
}
// Truncation errors
if _, err := UnmarshalParams(pbytes[:len(pbytes)-1]); err == nil {
t.Errorf("UnmarshalParams succeeded on truncated input")
}
if _, err := UnmarshalPrivateKey(bbParams, skbytes[:len(skbytes)-1]); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on truncated input")
}
// Extension errors
if _, err := UnmarshalParams(append(pbytes, 0)); err == nil {
t.Errorf("UnmarshalParams succeeded on extended input")
}
if _, err := UnmarshalPrivateKey(bbParams, append(skbytes, 0)); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on extended input")
}
// Zero length (no valid header either)
if _, err := UnmarshalParams(nil); err == nil {
t.Errorf("UnmarshalParams succeeded on nil input")
}
if _, err := UnmarshalParams([]byte{}); err == nil {
t.Errorf("UnmarshalParams succeeded on zero length input")
}
if _, err := UnmarshalPrivateKey(bbParams, nil); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on nil input")
}
if _, err := UnmarshalPrivateKey(bbParams, []byte{}); err == nil {
t.Errorf("UnmarshalPrivateKey succeeded on zero length input")
}
}
func TestBB1Marshaling(t *testing.T) { testMarshaling(t, SetupBB1) }
func TestBB2Marshaling(t *testing.T) { testMarshaling(t, SetupBB2) }
var (
benchmarkmlen = 64
benchmarkm = make([]byte, benchmarkmlen)
bb1, bb1SK, bb1C = initSchemeParams(SetupBB1)
bb2, bb2SK, bb2C = initSchemeParams(SetupBB2)
)
func initSchemeParams(setup SetupFunc) (Master, PrivateKey, []byte) {
var (
err error
bbParams Master
bbSK PrivateKey
bbC []byte
)
if bbParams, err = setup(); err != nil {
panic(err)
}
if bbSK, err = bbParams.Extract("alice"); err != nil {
panic(err)
}
if _, err := rand.Read(benchmarkm[:]); err != nil {
panic(err)
}
overhead := bbParams.Params().CiphertextOverhead()
bbC = make([]byte, benchmarkmlen+overhead)
if err := bbParams.Params().Encrypt("alice", benchmarkm, bbC); err != nil {
panic(err)
}
return bbParams, bbSK, bbC
}
func benchmarkExtractBB(b *testing.B, bb Master) {
for i := 0; i < b.N; i++ {
if _, err := bb.Extract("alice"); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkExtractBB1(b *testing.B) { benchmarkExtractBB(b, bb1) }
func BenchmarkExtractBB2(b *testing.B) { benchmarkExtractBB(b, bb2) }
func benchmarkEncryptBB(b *testing.B, bb Master) {
p := bb.Params()
C := make([]byte, benchmarkmlen+p.CiphertextOverhead())
for i := 0; i < b.N; i++ {
if err := p.Encrypt("alice", benchmarkm, C); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkEncryptBB1(b *testing.B) { benchmarkEncryptBB(b, bb1) }
func BenchmarkEncryptBB2(b *testing.B) { benchmarkEncryptBB(b, bb2) }
func benchmarkDecryptBB(b *testing.B, bbSK PrivateKey, bbC []byte) {
m := make([]byte, benchmarkmlen)
for i := 0; i < b.N; i++ {
if err := bbSK.Decrypt(bbC, m); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkDecryptBB1(b *testing.B) { benchmarkDecryptBB(b, bb1SK, bb1C) }
func BenchmarkDecryptBB2(b *testing.B) { benchmarkDecryptBB(b, bb2SK, bb2C) }