func newEncWriter(w io.Writer, secrets *Secrets) (*encWriter, error) { nonce, err := genKey(48) if err != nil { return nil, err } digester := hmac.New(sha512.New384, secrets.chunkMaster) digester.Write([]byte("\000chunk encryption\000")) digester.Write(nonce) digester.Write([]byte{0x01, 0x80}) derivedKey := digester.Sum(nil) key := derivedKey[0:32] iv := derivedKey[32:48] aesCypher, err := aes.NewCipher(key) if err != nil { return nil, err } cypher := cipher.NewCTR(aesCypher, iv) authHMAC := hmac.New(sha512.New384, secrets.chunkAuthentication) writer := io.MultiWriter(w, authHMAC) _, err = writer.Write([]byte{0}) // version if err != nil { return nil, err } _, err = writer.Write(nonce) if err != nil { return nil, err } authHMAC.Write(key) authHMAC.Write(iv) stream := cipher.StreamWriter{S: cypher, W: writer} n, err := stream.Write([]byte{1}) // compression always true if err != nil { return nil, err } if n != 1 { return nil, fmt.Errorf("Out-of-sync keystream") } return &encWriter{writer, stream, authHMAC, 50}, nil }
func (rw *rlpxFrameRW) WriteMsg(msg Msg) error { ptype, _ := rlp.EncodeToBytes(msg.Code) // write header headbuf := make([]byte, 32) fsize := uint32(len(ptype)) + msg.Size if fsize > maxUint24 { return errors.New("message size overflows uint24") } putInt24(fsize, headbuf) // TODO: check overflow copy(headbuf[3:], zeroHeader) rw.enc.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now encrypted // write header MAC copy(headbuf[16:], updateMAC(rw.egressMAC, rw.macCipher, headbuf[:16])) if _, err := rw.conn.Write(headbuf); err != nil { return err } // write encrypted frame, updating the egress MAC hash with // the data written to conn. tee := cipher.StreamWriter{S: rw.enc, W: io.MultiWriter(rw.conn, rw.egressMAC)} if _, err := tee.Write(ptype); err != nil { return err } if _, err := io.Copy(tee, msg.Payload); err != nil { return err } if padding := fsize % 16; padding > 0 { if _, err := tee.Write(zero16[:16-padding]); err != nil { return err } } // write frame MAC. egress MAC hash is up to date because // frame content was written to it as well. fmacseed := rw.egressMAC.Sum(nil) mac := updateMAC(rw.egressMAC, rw.macCipher, fmacseed) _, err := rw.conn.Write(mac) return err }
func writeSecrets(secrets *Secrets, backend Backend) (err error) { /* To write a secrets file: PBKDF2 the user's password with a random 32-byte salt under SHA-384; use this to generate 80 bytes of keying material. The first 32 bytes form an AES-256 encryption key; the next 48 bytes form an HMAC-SHA-384 authentication key. */ passphrase := termios.PasswordConfirm("Enter passphrase: ", "Repeat passphrase: ") salt := make([]byte, 32) n, err := rand.Reader.Read(salt) if err != nil { return err } if n != 32 { return fmt.Errorf("Could not read enough random bytes for salt") } iterations := 131072 // magic number, about 1 second's worth of time on my lappop secretsKeys := pbkdf2.Key([]byte(passphrase), salt, iterations, 80, sha512.New384) secretsEncKey := secretsKeys[:32] secretsAuthKey := secretsKeys[32:] secretsKeysDigest := sha512.New384() secretsKeysDigest.Write(secretsKeys) secretsKeysHash := secretsKeysDigest.Sum(nil) authHMAC := hmac.New(sha512.New384, secretsAuthKey) file := bytes.NewBuffer(nil) writer := io.MultiWriter(file, authHMAC) version := []byte{0} n, err = writer.Write(version) if err != nil { return err } if n != 1 { return fmt.Errorf("Error writing secrets file") } n, err = writer.Write(salt) if err != nil { return err } if n != len(salt) { return fmt.Errorf("Error writing secrets file") } iterBig := big.NewInt(int64(iterations)) iterBytes := iterBig.Bytes() iterBytes = append(make([]byte, 8-len(iterBytes)), iterBytes...) n, err = writer.Write(iterBytes) if err != nil { return err } if n != len(iterBytes) { return fmt.Errorf("Error writing secrets file") } n, err = writer.Write(secretsKeysHash) if err != nil { return err } if n != len(secretsKeysHash) { return fmt.Errorf("Error writing secrets file") } iv, err := genKey(16) if err != nil { return err } n, err = writer.Write(iv) if err != nil { return err } if n != len(iv) { return fmt.Errorf("Error writing secrets file") } cypher, err := aes.NewCipher(secretsEncKey) if err != nil { return err } ctrWriter := cipher.StreamWriter{S: cipher.NewCTR(cypher, iv), W: writer} n, err = ctrWriter.Write(secrets.metadataMaster) if err != nil { return err } if n != len(secrets.metadataMaster) { return fmt.Errorf("Error writing secrets file") } n, err = ctrWriter.Write(secrets.metadataAuthentication) if err != nil { return err } if n != len(secrets.metadataAuthentication) { return fmt.Errorf("Error writing secrets file") } n, err = ctrWriter.Write(secrets.metadataStorage) if err != nil { return err } if n != len(secrets.metadataStorage) { return fmt.Errorf("Error writing secrets file") } n, err = ctrWriter.Write(secrets.chunkMaster) if err != nil { return err } if n != len(secrets.chunkMaster) { return fmt.Errorf("Error writing secrets file") } n, err = ctrWriter.Write(secrets.chunkAuthentication) if err != nil { return err } if n != len(secrets.chunkAuthentication) { return fmt.Errorf("Error writing secrets file") } n, err = ctrWriter.Write(secrets.chunkStorage) if err != nil { return err } if n != len(secrets.chunkStorage) { return fmt.Errorf("Error writing secrets file") } authSum := authHMAC.Sum(nil) n, err = writer.Write(authSum) if err != nil { return err } if n != len(authSum) { return fmt.Errorf("Error writing secrets file") } return backend.WriteSecrets(hex.EncodeToString(secrets.Id()), file.Bytes()) }