// keyExchange is a convenience function that takes keys as byte slices, // copying them into the appropriate arrays. func keyExchange(shared *[32]byte, priv, pub []byte) { // Copy the private key and wipe it, as it will no longer be needed. var kexPriv [32]byte copy(kexPriv[:], priv) util.Zero(priv) var kexPub [32]byte copy(kexPub[:], pub) box.Precompute(shared, &kexPub, &kexPriv) util.Zero(kexPriv[:]) }
// FinishKEX verifies the signed public key. If it is valid, it will // carry out an ECDH key agreement, zeroise the private key, and store // the shared key. func (kex *Session) FinishKEX(signer *ecdsa.PublicKey, signed []byte) error { var skey signedKey rest, err := asn1.Unmarshal(signed, &skey) if err != nil { return err } else if len(rest) != 0 { return errors.New("eckex: trailing data in key exchange") } hashed := sha256.Sum256(skey.Public) if !ecdsa.Verify(signer, hashed[:], skey.R, skey.S) { return errors.New("eckex: verification failure") } pub, err := unpackECPKIX(skey.Public) if err != nil { return err } priv, err := x509.ParseECPrivateKey(kex.priv) util.Zero(kex.priv) if err != nil { return err } kex.shared, err = nistecdh.ECDH(priv, pub) kex.shared = kex.shared[:32] return err }
// deriveKey generates a new NaCl key from a passphrase and salt. func deriveKey(pass, salt []byte) (*[secret.KeySize]byte, error) { var naclKey = new([secret.KeySize]byte) key, err := scrypt.Key(pass, salt, 1048576, 8, 1, secret.KeySize) if err != nil { return nil, err } copy(naclKey[:], key) util.Zero(key) return naclKey, 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 }
// Decrypt recovers a message encrypted using a passphrase. func Decrypt(pass, message []byte) ([]byte, error) { if len(message) < Overhead { log.Print("length") return nil, ErrDecrypt } key, err := deriveKey(pass, message[:SaltSize]) if err != nil { log.Print("scrypt") return nil, ErrDecrypt } out, err := secret.Decrypt(key, message[SaltSize:]) util.Zero(key[:]) // Zero key immediately after if err != nil { log.Printf("decrypt") return nil, ErrDecrypt } return out, nil }
// Close zeroises the keys in the session. Once a session is closed, // the traffic that was sent over the channel can no longer be decrypted // and any attempts at sending or receiving messages over the channel // will fail. func (s *Session) Close() error { util.Zero(s.sendKey[:]) util.Zero(s.recvKey[:]) return nil }
// Close zeroises any remaining key material. func (kex *Session) Close() { util.Zero(kex.priv) util.Zero(kex.shared) }