func newEncReader(r io.Reader, secrets *Secrets, length int) (reader *encReader, err error) { buf := make([]byte, 48) n, err := r.Read(buf[:1]) if n != 1 { return nil, fmt.Errorf("Error decoding chunk") } if err != nil { return nil, err } version := buf[0] if version != 0 { return nil, fmt.Errorf("Unsupported chunk version %d", version) } n, err = r.Read(buf) if n != 48 { return nil, fmt.Errorf("Error decoding chunk") } if err != nil { return nil, err } nonce := make([]byte, 48) copy(nonce, buf) 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) authHMAC.Write([]byte{0}) authHMAC.Write(nonce) authHMAC.Write(key) authHMAC.Write(iv) cypherStream := cipher.StreamReader{S: cypher, R: io.TeeReader(r, authHMAC)} n, err = cypherStream.Read(buf[0:1]) if n != 1 { return nil, fmt.Errorf("Error decoding chunk") } if err != nil { return nil, err } //compressed_p := buf[0] != 0 return &encReader{source: r, reader: cypherStream, authHMAC: authHMAC, length: length - 48, numRead: 50}, nil }
func ReadSecrets(backend Backend) (secrets *Secrets, err error) { passphrase := termios.Password("Enter passphrase: ") encSecrets, err := backend.ReadSecrets() if err != nil { return nil, err } file := bytes.NewBuffer(encSecrets) version := make([]byte, 1) n, err := file.Read(version) if err != nil { return nil, err } if n != 1 { return nil, fmt.Errorf("Error reading secrets file") } if version[0] != 0 { return nil, fmt.Errorf("Cannot read file version %d", version[0]) } salt := make([]byte, 32) n, err = file.Read(salt) if err != nil { return nil, err } if n != len(salt) { return nil, fmt.Errorf("Error reading secrets file") } iterBytes := make([]byte, 8) n, err = file.Read(iterBytes) if err != nil { return nil, err } if n != len(iterBytes) { return nil, fmt.Errorf("Error reading secrets file") } iterBig := big.NewInt(0) iterBig.SetBytes(iterBytes) iterations := int(iterBig.Int64()) // FIXME: add some code to the iterations and rewrite the file // if the time to generate a key is too far from the target of 1 // second secretsKeys := pbkdf2.Key([]byte(passphrase), salt, iterations, 80, sha512.New384) secretsDigest := sha512.New384() // don't need to check for errors, per spec secretsDigest.Write(secretsKeys) secretsKeysHash := secretsDigest.Sum(nil) storedHash := make([]byte, len(secretsKeysHash)) n, err = file.Read(storedHash) if err != nil { return nil, err } if n != len(storedHash) { return nil, fmt.Errorf("Error reading secrets file") } if !bytes.Equal(storedHash, secretsKeysHash) { return nil, fmt.Errorf("Bad password") } iv := make([]byte, 16) n, err = file.Read(iv) if err != nil { return nil, err } if n != len(iv) { return nil, fmt.Errorf("Error reading secrets file") } secretsEncKey := secretsKeys[:32] secretsAuthKey := secretsKeys[32:] authHMAC := hmac.New(sha512.New384, secretsAuthKey) authHMAC.Write(version) authHMAC.Write(salt) authHMAC.Write(iterBytes) authHMAC.Write(secretsKeysHash) authHMAC.Write(iv) reader := io.TeeReader(file, authHMAC) cypher, err := aes.NewCipher(secretsEncKey) if err != nil { return nil, err } ctrReader := cipher.StreamReader{S: cipher.NewCTR(cypher, iv), R: reader} secrets = &Secrets{} secrets.metadataMaster = make([]byte, 32) n, err = ctrReader.Read(secrets.metadataMaster) if err != nil { ZeroSecrets(secrets) return nil, err } if n != len(secrets.metadataMaster) { ZeroSecrets(secrets) return nil, fmt.Errorf("Error reading secrets file") } secrets.metadataAuthentication = make([]byte, 48) n, err = ctrReader.Read(secrets.metadataAuthentication) if err != nil { ZeroSecrets(secrets) return nil, err } if n != len(secrets.metadataAuthentication) { ZeroSecrets(secrets) return nil, fmt.Errorf("Error reading secrets file") } secrets.metadataStorage = make([]byte, 48) n, err = ctrReader.Read(secrets.metadataStorage) if err != nil { ZeroSecrets(secrets) return nil, err } if n != len(secrets.metadataStorage) { ZeroSecrets(secrets) return nil, fmt.Errorf("Error reading secrets file") } secrets.chunkMaster = make([]byte, 32) n, err = ctrReader.Read(secrets.chunkMaster) if err != nil { ZeroSecrets(secrets) return nil, err } if n != len(secrets.chunkMaster) { ZeroSecrets(secrets) return nil, fmt.Errorf("Error reading secrets file") } secrets.chunkAuthentication = make([]byte, 48) n, err = ctrReader.Read(secrets.chunkAuthentication) if err != nil { ZeroSecrets(secrets) return nil, err } if n != len(secrets.chunkAuthentication) { ZeroSecrets(secrets) return nil, fmt.Errorf("Error reading secrets file") } secrets.chunkStorage = make([]byte, 48) n, err = ctrReader.Read(secrets.chunkStorage) if err != nil { ZeroSecrets(secrets) return nil, err } if n != len(secrets.chunkStorage) { ZeroSecrets(secrets) return nil, fmt.Errorf("Error reading secrets file") } calcSum := authHMAC.Sum(nil) authSum := make([]byte, authHMAC.Size()) n, err = reader.Read(authSum) if err != nil && err != io.EOF { return nil, err } if n != len(authSum) { return nil, fmt.Errorf("Error reading secrets file: %d", n) } if !bytes.Equal(calcSum, authSum) { return nil, fmt.Errorf("Corrupted secrets file") } return secrets, nil }