// Encrypt secures a message using AES-CBC-HMAC-SHA-256 with a random // nonce. func Encrypt(key, message []byte) ([]byte, error) { if len(key) != KeySize { return nil, ErrEncrypt } iv, err := util.RandBytes(NonceSize) if err != nil { return nil, ErrEncrypt } pmessage := pad(message) ct := make([]byte, len(pmessage)) // NewCipher only returns an error with an invalid key size, // but the key size was checked at the beginning of the function. c, _ := aes.NewCipher(key[:CKeySize]) ctr := cipher.NewCBCEncrypter(c, iv) ctr.CryptBlocks(ct, pmessage) h := hmac.New(sha256.New, key[CKeySize:]) ct = append(iv, ct...) h.Write(ct) ct = h.Sum(ct) return ct, nil }
func TestSetupDB(t *testing.T) { var err error testKey, err = util.RandBytes(KeySize) if err != nil { t.Fatalf("%v", err) } keyDB[42] = testKey keyDB[43] = testKey }
// Encrypt secures a message to the peer's public key using an ephemeral // key pair. func Encrypt(peer *[32]byte, message []byte) ([]byte, error) { pub, priv, err := box.GenerateKey(rand.Reader) if err != nil { return nil, ErrEncrypt } var nonce [24]byte nbs, err := util.RandBytes(24) if err != nil { return nil, ErrEncrypt } copy(nonce[:], nbs) nbs = box.Seal(nbs, message, &nonce, peer, priv) out := make([]byte, 32, 32+len(nbs)) copy(out, pub[:]) return append(out, nbs...), nil }
// Encrypt secures a message using a passphrase. func Encrypt(pass, message []byte) ([]byte, error) { salt, err := util.RandBytes(SaltSize) if err != nil { return nil, ErrEncrypt } key, err := deriveKey(pass, salt) if err != nil { return nil, ErrEncrypt } out, err := secret.Encrypt(key, message) util.Zero(key[:]) // Zero key immediately after if err != nil { return nil, ErrEncrypt } out = append(salt, out...) return out, nil }
// EncryptWithID secures a message and prepends a 4-byte sender ID // to the message. func EncryptWithID(key, message []byte, sender uint32) ([]byte, error) { buf := make([]byte, 4) binary.BigEndian.PutUint32(buf, sender) c, err := aes.NewCipher(key) if err != nil { return nil, ErrEncrypt } gcm, err := cipher.NewGCM(c) if err != nil { return nil, ErrEncrypt } nonce, err := util.RandBytes(NonceSize) if err != nil { return nil, ErrEncrypt } buf = append(buf, nonce...) buf = gcm.Seal(buf, nonce, message, buf[:4]) return buf, nil }
// GenerateNonce generates a new AES-CTR nonce. func GenerateNonce() ([]byte, error) { return util.RandBytes(NonceSize) }
// GenerateKey generates a new AES-256 and HMAC-SHA-384 key. func GenerateKey() ([]byte, error) { return util.RandBytes(KeySize) }
func TestSessionListen(t *testing.T) { pub, priv, err := GenerateKeyPair() if err != nil { t.Fatalf("%v", err) } conn := testio.NewBufferConn() conn.WritePeer(pub[:]) aliceSession, err = Listen(conn) if err != nil { t.Fatalf("%v", err) } var peer [64]byte _, err = conn.ReadClient(peer[:]) if err != nil { t.Fatalf("%v", err) } bobSession = &Session{ recvKey: new([32]byte), sendKey: new([32]byte), Channel: testio.NewBufCloser(nil), } bobSession.KeyExchange(priv, &peer, true) aliceSession.Channel = bobSession.Channel err = aliceSession.Send(testMessage) if err != nil { t.Fatalf("%v", err) } out, err := bobSession.Receive() if err != nil { t.Fatalf("%v", err) } // The NBA is always listening, on and off the court. oldMessage = out if !bytes.Equal(out, testMessage) { t.Fatal("recovered message doesn't match original") } for i := 0; i < 4; i++ { randMessage, err := util.RandBytes(128) if err != nil { t.Fatalf("%v", err) } err = aliceSession.Send(randMessage) if err != nil { t.Fatalf("%v", err) } out, err = bobSession.Receive() if err != nil { t.Fatal("%v", err) } if !bytes.Equal(out, randMessage) { t.Fatal("recovered message doesn't match original") } } // NBA injects an old message into the channel. Damn those hoops! bobSession.Channel.Write(oldMessage) _, err = bobSession.Receive() if err == nil { t.Fatal("NBA wins, you lose") } }