Пример #1
0
// MarshalSecretStore serialises and encrypts the data store to a byte
// slice suitable for writing to disk.
func MarshalSecretStore(s *SecretStore, m secret.ScryptMode) ([]byte, bool) {
	if !s.Valid() {
		return nil, false
	}

	out, err := json.Marshal(s)
	if err != nil {
		return nil, false
	}
	defer util.Zero(out)

	salt := util.RandBytes(saltSize)
	if salt == nil {
		return nil, false
	}

	key := secret.DeriveKeyStrength(s.passphrase, salt, m)
	if key == nil {
		return nil, false
	}
	defer util.Zero(key[:])

	enc, ok := secret.Encrypt(key, out)
	if !ok {
		return nil, false
	}
	defer s.Zero()

	enc = append(salt, enc...)
	return enc, true
}
Пример #2
0
// NewSession sets up a new session. The Last field should be sent
// to the client. The returned public key should be sent to the
// user for generating a shared MAC key. The authenticator should ensure
// some mechanism for expiring sessions exists.
func NewSession(pub []byte) (*Authenticator, []byte, error) {
	next := util.RandBytes(sessionLength)
	if next == nil {
		return nil, nil, errors.New("auth: PRNG failure")
	}

	ephemeral, err := public.GenerateKey()
	if err != nil || !ephemeral.Valid() {
		return nil, nil, errors.New("auth: failed to set up session key")
	}

	// Validated that the key was correct previously.
	ephemeralPublic, _ := public.MarshalPublic(ephemeral.PublicKey)

	peer, err := public.UnmarshalPublic(pub)
	if err != nil {
		return nil, nil, err
	}

	shared := public.KeyExchange(ephemeral, peer)

	return &Authenticator{
		Type:   TypeSession,
		Last:   hex.EncodeToString(next),
		Secret: shared,
	}, ephemeralPublic, nil
}
Пример #3
0
// GenerateKey returns a randomly generated secretbox key. Typically,
// you should use DeriveKey to get a key from a passphrase
// instead. Returns nil on failure.
func GenerateKey() *[KeySize]byte {
	var key [KeySize]byte
	rb := util.RandBytes(KeySize)
	if rb == nil || len(rb) != KeySize {
		return nil
	}
	defer util.Zero(rb)

	copy(key[:], rb)
	return &key
}
Пример #4
0
func TestDeriveKey(t *testing.T) {
	salt := util.RandBytes(SaltSize)
	if k := DeriveKey(password, salt); k == nil {
		t.Fatal("secret: failed to derive key")
	}

	n := scryptParams.N
	scryptParams.N = 0
	if k := DeriveKey(password, salt); k != nil {
		t.Fatal("secret: should fail to derive key with invalid Scrypt params")
	}
	scryptParams.N = n
}
Пример #5
0
// NewGoogleTOTP generates a new Google-authenticator standard TOTP
// token.
func NewGoogleTOTP(label string) (*Authenticator, *UserTOTP, error) {
	key := util.RandBytes(sha1.Size)
	if key == nil {
		return nil, nil, errors.New("auth: PRNG failure")
	}

	auth, _ := ImportGoogleTOTP(key)
	ud, err := ExportUserTOTP(auth, label)
	if err != nil {
		return nil, nil, err
	}

	return auth, ud, nil
}
Пример #6
0
func TestUnlockKeyFail(t *testing.T) {
	var password = []byte("password")
	var message = []byte("this is not a valid private key")
	salt := util.RandBytes(saltSize)

	key := secret.DeriveKey(password, salt)
	out, ok := secret.Encrypt(key, message)
	if !ok {
		t.Fatal("public: encrypt failed")
	}

	out = append(salt, out...)
	_, ok = UnlockKey(out, password)
	if ok {
		t.Fatal("public: unlock key should fail with invalid private key")
	}
}
Пример #7
0
func TestLockKey(t *testing.T) {
	key, err := GenerateKey()
	if err != nil {
		t.Fatalf("Failed to generate test key: %v", err)
	}

	out, ok := EncryptAndSign(testKey, key.PublicKey, message)
	if !ok {
		t.Fatal("Failed to encrypt and sign message.")
	}

	locked, ok := LockKey(key, []byte("this is my password"))
	if !ok {
		t.Fatal("Failed to lock key.")
	}

	_, ok = UnlockKey(locked, []byte("this is my password."))
	if ok {
		t.Fatal("Unlocked with wrong passphrase.")
	}

	priv, ok := UnlockKey(locked, []byte("this is my password"))
	if !ok {
		t.Fatal("Unlocking key failed.")
	}

	recovered, ok := DecryptAndVerify(priv, testKey.PublicKey, out)
	if !ok {
		t.Fatal("Failed to decrypt and verify message.")
	}

	if !bytes.Equal(message, recovered) {
		t.Fatalf("Corrupt message.\nRecovered: %x\nMessage: %x\n",
			recovered, message)
	}

	salt := util.RandBytes(saltSize)
	buf := bytes.NewBuffer(salt)
	util.SetPRNG(buf)
	_, ok = LockKey(priv, []byte("password"))
	if ok {
		t.Fatal("public: expect locking to fail with bad PRNG")
	}
	util.SetPRNG(rand.Reader)
}
Пример #8
0
// EncryptFile securely stores the encoded blob under the filename.
func EncryptFile(filename string, passphrase, encoded []byte) (err error) {
	salt := util.RandBytes(SaltSize)
	if salt == nil {
		err = errors.New("password: failed to generate new salt")
		return
	}
	defer util.Zero(encoded)

	key := DeriveKey(passphrase, salt)
	data, ok := Encrypt(key, encoded)
	if !ok {
		data = nil
		err = errors.New("password: failed to encrypt data")
		return
	}

	data = append(salt, data...)
	err = ioutil.WriteFile(filename, data, 0600)
	return
}
Пример #9
0
func TestDeriveKey(t *testing.T) {
	salt := util.RandBytes(SaltSize)
	if k := DeriveKey(password, salt); k == nil {
		t.Fatal("secret: failed to derive key")
	}

	if k := DeriveKey(password, salt); k == nil {
		t.Fatal("secret: key derivation failure")
	}

	if k := DeriveKeyStrength(password, salt, ScryptInteractive); k == nil {
		t.Fatal("secret: key derivation failure")
	}

	scryptMode[-1] = scryptParams{0, 0, 0}
	if k := DeriveKeyStrength(password, salt, -1); k != nil {
		t.Fatal("secret: should fail to derive key with invalid Scrypt parameters")
	}
	delete(scryptMode, -1)
}
Пример #10
0
func TestEncryptFile(t *testing.T) {
	defer os.Remove(testEncryptedFile)
	err := EncryptFile(testEncryptedFile, password, dup(message))
	if err != nil {
		t.Fatalf("%v", err)
	}

	out, err := DecryptFile(testEncryptedFile, password)
	if err != nil {
		t.Fatalf("%v", err)
	}

	if !bytes.Equal(out, message) {
		t.Fatal("secret: decrypted file doesn't match original message")
	}

	if _, err = DecryptFile(testNoSuchFile, password); err == nil {
		t.Fatal("secret: decrypt file should fail with IO error")
	}

	if _, err = DecryptFile(testUnencryptedFile, password); err == nil {
		t.Fatal("secret: decrypt file should fail with unencrypted file")
	}

	salt := util.RandBytes(SaltSize)
	buf := &bytes.Buffer{}
	util.SetPRNG(buf)
	err = EncryptFile(testEncryptedFile, password, dup(message))
	if err == nil {
		t.Fatal("secret: encrypt file should fail with bad PRNG")
	}

	buf.Write(salt)
	err = EncryptFile(testEncryptedFile, password, dup(message))
	if err == nil {
		t.Fatal("secret: encrypt file should fail with bad PRNG")
	}
	util.SetPRNG(rand.Reader)
}
Пример #11
0
// ValidateSession ensures that the OTP provided contains the next
// value and the appropriate HMAC for the session.
func ValidateSession(auth *Authenticator, otp string) (bool, error) {
	if (auth == nil) || (auth.Type != TypeSession) {
		return false, ErrInvalidAuthenticator
	}

	otpBytes, err := hex.DecodeString(otp)
	if err != nil {
		return false, err
	}

	if len(otpBytes) != 2*sessionLength {
		return false, ErrValidationFail
	}

	lastBytes, err := hex.DecodeString(auth.Last)
	if err != nil {
		return false, err
	}

	h := hmac.New(sha256.New, auth.Secret)
	h.Write(lastBytes)
	expected := h.Sum(nil)

	if !bytes.Equal(otpBytes[:sessionLength], lastBytes) {
		return false, ErrValidationFail
	}

	if !hmac.Equal(otpBytes[sessionLength:], expected) {
		return false, ErrValidationFail
	}

	next := util.RandBytes(sessionLength)
	if next == nil {
		return false, errors.New("auth: PRNG failure")
	}

	auth.Last = hex.EncodeToString(next)
	return true, nil
}
Пример #12
0
// LockKey secures the private key with the passphrase, using Scrypt
// and NaCl's secretbox.
func LockKey(priv *PrivateKey, passphrase []byte) ([]byte, bool) {
	out, err := MarshalPrivate(priv)
	if err != nil {
		return nil, false
	}
	defer util.Zero(out)

	salt := util.RandBytes(saltSize)
	if salt == nil {
		return nil, false
	}

	key := secret.DeriveKey(passphrase, salt)
	defer util.Zero(key[:])

	out, ok := secret.Encrypt(key, out)
	if !ok {
		return nil, false
	}

	out = append(salt, out...)
	return out, true
}
Пример #13
0
func main() {
	flArmour := flag.Bool("a", false, "armour output")
	flOutDir := flag.String("o", ".", "output directory")
	flOutfile := flag.String("f", "passcrypt.enc", "pack file")
	flShowManifest := flag.Bool("l", false, "list the files in the archive")
	flUnpack := flag.Bool("u", false, "unpack the archive")
	flag.BoolVar(&verbose, "v", false, "verbose mode")
	flVersion := flag.Bool("V", false, "display version and exit")
	flag.Parse()

	if *flVersion {
		fmt.Println("passcrypt version", util.VersionString())
		os.Exit(0)
	}

	if *flUnpack || *flShowManifest {
		if flag.NArg() != 1 {
			util.Errorf("Only one file may be unpacked at a time.\n")
			os.Exit(1)
		}

		in, err := ioutil.ReadFile(flag.Arg(0))
		if err != nil {
			util.Errorf("%v\n", err)
			os.Exit(1)
		}

		if p, _ := pem.Decode(in); p != nil {
			if p.Type != header {
				util.Errorf("Wrong header for archive.\n")
				os.Exit(1)
			}
			in = p.Bytes
		}

		if len(in) <= saltLength {
			util.Errorf("Invalid archive.\n")
			os.Exit(1)
		}
		salt := in[:saltLength]
		in = in[saltLength:]

		passphrase, err := readpass.PasswordPromptBytes("Password: "******"%v\n", err)
			os.Exit(1)
		}

		key := secret.DeriveKey(passphrase, salt)
		if key == nil {
			util.Errorf("Failed to derive key.n\n")
			os.Exit(1)
		}

		in, ok := secret.Decrypt(key, in)
		if !ok {
			util.Errorf("Decryption failed.\n")
			os.Exit(1)
		}
		defer util.Zero(in)

		if *flUnpack {
			err = unpackFiles(in, *flOutDir)
			if err != nil {
				util.Errorf("%v\n", err)
				os.Exit(1)
			}
		} else if *flShowManifest {
			var files []File
			_, err := asn1.Unmarshal(in, &files)
			if err != nil {
				util.Errorf("%v\n", err)
				os.Exit(1)
			}

			fmt.Println("Manifest for", flag.Arg(0))
			fmt.Printf("\n")
			for _, file := range files {
				fmt.Printf("\t%s", file.Path)
				if os.FileMode(file.Mode).IsDir() {
					fmt.Printf("/")
				}
				fmt.Printf("\n")
			}
		}
		return
	}

	if flag.NArg() == 0 {
		return
	}

	passphrase, err := readpass.PasswordPromptBytes("Password: "******"%v\n", err)
		os.Exit(1)
	}

	salt := util.RandBytes(saltLength)
	if salt == nil {
		util.Errorf("Failed to generate a random salt.\n")
		os.Exit(1)
	}

	key := secret.DeriveKey(passphrase, salt)
	if key == nil {
		util.Errorf("Failed to derive key.n\n")
		os.Exit(1)
	}

	out, err := packFiles(flag.Args())
	if err != nil {
		util.Errorf("%v\n", err)
		os.Exit(1)
	}

	var ok bool
	out, ok = secret.Encrypt(key, out)
	if !ok {
		util.Errorf("Encryption failed.\n")
		os.Exit(1)
	}

	out = append(salt, out...)

	if *flArmour {
		p := &pem.Block{
			Type:  header,
			Bytes: out,
		}
		out = pem.EncodeToMemory(p)
	}

	err = ioutil.WriteFile(*flOutfile, out, 0644)
	if err != nil {
		util.Errorf("%v\n", err)
		os.Exit(1)
	}
}