// Returns a new Reader that reads from r // // The header section storing the salt and keys is read from r to verify the file is // actually a psafe3 file and the password is correct. // // All reads from this reader will return unencrypted data. func NewReader(r io.Reader, password string) (*Reader, error) { reader := &Reader{r: r, password: password} var header psv3Header binary.Read(r, binary.LittleEndian, &header) if string(header.Tag[:]) != "PWS3" { return nil, ErrBadFileType } sk := computeStretchKey(header.Salt[:], []byte(password), int(header.Iter)) hashsk := sha256.Sum256(sk) if hashsk != header.HashPPrime { return nil, ErrInvalidPassword } var key, hmacKey [32]byte tfish, _ := twofish.NewCipher(sk) tfish.Decrypt(key[:16], header.B1[:]) tfish.Decrypt(key[16:], header.B2[:]) tfish.Decrypt(hmacKey[:16], header.B3[:]) tfish.Decrypt(hmacKey[16:], header.B4[:]) tfish, _ = twofish.NewCipher(key[:]) reader.tfishDecrypter = cipher.NewCBCDecrypter(tfish, header.IV[:]) reader.hmacHash = hmac.New(sha256.New, hmacKey[:]) return reader, nil }
func decrypt(blob []byte) { c, err := twofish.NewCipher(key) if err != nil { panic(err) } s := cipher.NewCFBDecrypter(c, iv) s.XORKeyStream(blob, blob) }
func encrypt_data(plain, keys []byte) ([]byte, error) { var iv, key []byte var block cipher.Block var stream cipher.Stream iv_offset := TotalIVLen res := make([]byte, len(plain)+iv_offset) iv = res[iv_offset-SalsaIVLen : iv_offset] _, err := rand.Read(iv) if err != nil { return nil, err } // For some reason salsa20 API is different key_array := new([32]byte) copy(key_array[:], keys[cipherKeyLen*2:]) salsa20.XORKeyStream(res[iv_offset:], plain, iv, key_array) iv_offset -= SalsaIVLen iv = res[iv_offset-IVLen : iv_offset] _, err = rand.Read(iv) if err != nil { return nil, err } key = keys[cipherKeyLen : cipherKeyLen*2] block, err = twofish.NewCipher(key) if err != nil { return nil, err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(res[iv_offset:], res[iv_offset:]) iv_offset -= IVLen iv = res[iv_offset-IVLen : iv_offset] _, err = rand.Read(iv) if err != nil { return nil, err } key = keys[:cipherKeyLen] block, err = aes.NewCipher(key) if err != nil { return nil, err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(res[iv_offset:], res[iv_offset:]) iv_offset -= IVLen if iv_offset != 0 { panic(fmt.Errorf("something went terribly wrong: iv_offset final value non-zero")) } return res, nil }
func decrypt_data(dst, data, keys []byte) error { var iv, key []byte var block cipher.Block var stream cipher.Stream var err error buffer := append([]byte{}, data...) iv_offset := IVLen iv = buffer[:iv_offset] key = keys[:cipherKeyLen] block, err = aes.NewCipher(key) if err != nil { return err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(buffer[iv_offset:], buffer[iv_offset:]) iv_offset += IVLen iv = buffer[iv_offset-IVLen : iv_offset] key = keys[cipherKeyLen : cipherKeyLen*2] block, err = twofish.NewCipher(key) if err != nil { return err } stream = cipher.NewCTR(block, iv) stream.XORKeyStream(buffer[iv_offset:], buffer[iv_offset:]) iv_offset += SalsaIVLen iv = buffer[iv_offset-SalsaIVLen : iv_offset] key_array := new([32]byte) copy(key_array[:], keys[cipherKeyLen*2:]) salsa20.XORKeyStream(dst, buffer[iv_offset:], iv, key_array) if len(buffer[iv_offset:]) != len(data)-TotalIVLen { return fmt.Errorf("something went terribly wrong: bufsz is wrong") } return nil }
// NewCipher creates a new Twofish cipher from the key. func (key TwofishKey) NewCipher() cipher.Block { // NOTE: NewCipher only returns an error if len(key) != 16, 24, or 32. cipher, _ := twofish.NewCipher(key[:]) return cipher }
// Write the password safe to an encrypted psafe3 file func OutputFile(outputfile, password string, safe Safe) error { outfile, err := os.Create(outputfile) if err != nil { log.Fatal(err) } defer outfile.Close() safe.Headers.LastSave = time.Now() safe.Headers.ProgramSave = "pwsafe 0.1" user, uerr := user.Current() if uerr == nil && user.Username != "" { safe.Headers.User = user.Username } if host, herr := os.Hostname(); herr == nil { safe.Headers.Host = host } fmt.Fprint(outfile, "PWS3") var randbytes [112]byte if _, rerr := rand.Read(randbytes[:]); rerr != nil { return rerr } salt := randbytes[:32] iv := randbytes[32:48] k := randbytes[48:80] l := randbytes[80:] outfile.Write(salt) binary.Write(outfile, binary.LittleEndian, uint32(iterations)) sk := computeStretchKey(salt[:], []byte(password), iterations) hashsk := sha256.Sum256(sk) outfile.Write(hashsk[:]) var b1, b2, b3, b4 [16]byte tfish, _ := twofish.NewCipher(sk) tfish.Encrypt(b1[:], k[:16]) tfish.Encrypt(b2[:], k[16:]) tfish.Encrypt(b3[:], l[:16]) tfish.Encrypt(b4[:], l[16:]) binary.Write(outfile, binary.LittleEndian, b1[:]) binary.Write(outfile, binary.LittleEndian, b2[:]) binary.Write(outfile, binary.LittleEndian, b3[:]) binary.Write(outfile, binary.LittleEndian, b4[:]) outfile.Write(iv[:]) tfish, _ = twofish.NewCipher(k[:]) engine := cipher.NewCBCEncrypter(tfish, iv[:]) hmacEngine := hmac.New(sha256.New, l[:]) var buf bytes.Buffer var endSection, blockData [16]byte endSection[4] = 0xFF // Headers writeField(outfile, engine, hmacEngine, 0x00, []byte{safe.Headers.VersionMinor, safe.Headers.VersionMajor}) binary.Write(&buf, binary.LittleEndian, uint32(safe.Headers.LastSave.Unix())) writeField(outfile, engine, hmacEngine, 0x04, buf.Bytes()) buf.Reset() writeField(outfile, engine, hmacEngine, 0x06, []byte(safe.Headers.ProgramSave)) writeField(outfile, engine, hmacEngine, 0x07, []byte(safe.Headers.User)) writeField(outfile, engine, hmacEngine, 0x08, []byte(safe.Headers.Host)) engine.CryptBlocks(blockData[:], endSection[:]) outfile.Write(blockData[:]) for _, record := range safe.Records { id := uuid.NewV4() writeField(outfile, engine, hmacEngine, 0x01, id.Bytes()) writeField(outfile, engine, hmacEngine, 0x02, []byte(record.Group)) writeField(outfile, engine, hmacEngine, 0x03, []byte(record.Title)) writeField(outfile, engine, hmacEngine, 0x04, []byte(record.Username)) writeField(outfile, engine, hmacEngine, 0x05, []byte(record.Notes)) writeField(outfile, engine, hmacEngine, 0x06, []byte(record.Password)) binary.Write(&buf, binary.LittleEndian, uint32(record.CreationTime.Unix())) writeField(outfile, engine, hmacEngine, 0x07, buf.Bytes()) buf.Reset() writeField(outfile, engine, hmacEngine, 0x0d, []byte(record.Url)) writeField(outfile, engine, hmacEngine, 0x14, []byte(record.Email)) engine.CryptBlocks(blockData[:], endSection[:]) outfile.Write(blockData[:]) } outfile.Write([]byte("PWS3-EOFPWS3-EOF")) outfile.Write(hmacEngine.Sum(nil)) return nil }
func (e *Engine) twofish_ctr() error { return e.ctr(func(key []byte) (cipher.Block, error) { return twofish.NewCipher(key) }) }
func (e *Engine) untwofish_cfb() error { return e.uncfb(func(key []byte) (cipher.Block, error) { return twofish.NewCipher(key) }) }
// Twofish cipher func BenchmarkTwofish_1K(b *testing.B) { block, _ := twofish.NewCipher(buf[:16]) benchmarkBlock(b, block, 1024) }