2018-07-01 21:07:50 +02:00
// +build enable_trezor
2018-06-17 15:25:09 +02:00
package readpassword
import (
2018-06-26 20:06:42 +02:00
"bytes"
"log"
2018-06-17 15:25:09 +02:00
"os"
"github.com/rfjakob/gocryptfs/internal/exitcodes"
"github.com/rfjakob/gocryptfs/internal/tlog"
2018-06-25 23:52:55 +02:00
"github.com/xaionaro-go/cryptoWallet"
"github.com/xaionaro-go/cryptoWallet/vendors"
2018-06-17 15:25:09 +02:00
)
2018-06-25 22:27:15 +02:00
const (
// TrezorPayloadLen is the length of the payload data passed to Trezor's
// CipherKeyValue function.
2018-06-25 23:52:55 +02:00
TrezorPayloadLen = 32
trezorNonce = "" // the "nonce" is optional and has no use in here
trezorKeyName = "gocryptfs"
trezorKeyDerivationPath = ` m/10019'/0' `
2018-06-25 22:27:15 +02:00
)
2018-06-25 23:52:55 +02:00
func trezorGetPin ( title , description , ok , cancel string ) ( [ ] byte , error ) {
return Once ( "" , title ) , nil
}
func trezorGetConfirm ( title , description , ok , cancel string ) ( bool , error ) {
return false , nil // do not retry on connection failure
}
// Trezor reads 32 deterministically derived bytes from a
2018-06-17 15:25:09 +02:00
// SatoshiLabs Trezor USB security module.
// The bytes are pseudorandom binary data and may contain null bytes.
2018-06-25 23:52:55 +02:00
// This function either succeeds and returns 32 bytes or calls os.Exit to end
2018-06-17 15:25:09 +02:00
// the application.
2018-06-25 22:27:15 +02:00
func Trezor ( payload [ ] byte ) [ ] byte {
if len ( payload ) != TrezorPayloadLen {
tlog . Fatal . Printf ( "Invalid TrezorPayload length: wanted %d, got %d bytes\n" , TrezorPayloadLen , len ( payload ) )
os . Exit ( exitcodes . LoadConf )
}
2018-06-25 23:52:55 +02:00
// Find all trezor devices
trezors := cryptoWallet . Find ( cryptoWallet . Filter {
VendorID : & [ ] uint16 { vendors . GetVendorID ( "satoshilabs" ) } [ 0 ] ,
ProductIDs : [ ] uint16 { 1 /* Trezor One */ } ,
} )
// ATM, we require to one and only one trezor device to be connected.
// The support of multiple trezor devices is not implemented, yet.
if len ( trezors ) == 0 {
tlog . Fatal . Printf ( "Trezor device is not found. Check the connection." )
os . Exit ( exitcodes . TrezorError )
}
if len ( trezors ) > 1 {
tlog . Fatal . Printf ( "It's more than one Trezor device connected. This case is not implemented, yet. The number of currently connected devices: %v." , len ( trezors ) )
os . Exit ( exitcodes . TrezorError )
}
// Using the first found device
trezor := trezors [ 0 ]
// Trezor may ask for PIN or Passphrase. Setting the handler for this case.
trezor . SetGetPinFunc ( trezorGetPin )
// In some cases (like lost connection to the Trezor device and cannot
// reconnect) it's required to get a confirmation from the user to
// retry to reconnect. Setting the handler for this case.
trezor . SetGetConfirmFunc ( trezorGetConfirm )
// To reset the state of the device and check if it's initialized.
// If device is not initialized then trezor.Reset() will return an
// error.
err := trezor . Reset ( )
2018-06-17 15:25:09 +02:00
if err != nil {
2018-06-25 23:52:55 +02:00
tlog . Fatal . Printf ( "Cannot reset the Trezor device. Error: %v" , err . Error ( ) )
2018-06-17 15:25:09 +02:00
os . Exit ( exitcodes . TrezorError )
}
2018-06-25 23:52:55 +02:00
// To generate a deterministic key we trying to decrypt our
// predefined constant key using the Trezor device. The resulting key
// will depend on next variables:
// * the Trezor master key;
// * the passphrase (passed to the Trezor).
//
// The right key will be received only if both values (mentioned
// above) are correct.
//
// Note:
// Also the resulting key depends on this values (that we defined as
// constants above):
// * the key derivation path;
// * the "encrypted" payload;
// * the nonce;
// * the key name.
key , err := trezor . DecryptKey ( trezorKeyDerivationPath , payload , [ ] byte ( trezorNonce ) , trezorKeyName )
if err != nil {
tlog . Fatal . Printf ( "Cannot get the key from the Trezor device. Error description:\n\t%v" , err . Error ( ) )
os . Exit ( exitcodes . TrezorError )
}
2018-06-26 20:06:42 +02:00
// Sanity checks
if len ( key ) != TrezorPayloadLen {
log . Panicf ( "BUG: decrypted value has wrong length %d" , len ( key ) )
}
if bytes . Equal ( key , payload ) {
log . Panicf ( "BUG: payload and decrypted value are identical" )
}
zero := make ( [ ] byte , TrezorPayloadLen )
if bytes . Equal ( key , zero ) {
log . Panicf ( "BUG: decrypted value is all-zero" )
}
2018-06-25 23:52:55 +02:00
// Everything ok
return key
2018-06-17 15:25:09 +02:00
}