Beispiel #1
0
func (sec *AccountSecurity) ResetPassword(kms security.KMS, password string) (*AccountSecurity, error) {
	kek := sec.SystemKey.Clone()
	if err := kms.DecryptKey(&kek); err != nil {
		return nil, fmt.Errorf("key decryption error: %s", err)
	}
	kek.IV = make([]byte, ClientKeyType.BlockSize())
	copy(kek.IV, sec.Nonce)

	clientKey := security.KeyFromPasscode([]byte(password), sec.Nonce, sec.UserKey.KeyType)
	if err := kek.Encrypt(clientKey); err != nil {
		return nil, fmt.Errorf("key encryption error: %s", err)
	}

	var (
		mac [16]byte
		key [32]byte
	)
	copy(key[:], clientKey.Plaintext)
	poly1305.Sum(&mac, sec.Nonce, &key)

	nsec := &AccountSecurity{
		Nonce:     sec.Nonce,
		MAC:       mac[:],
		SystemKey: sec.SystemKey,
		UserKey:   kek,
		KeyPair:   sec.KeyPair,
	}
	return nsec, nil
}
Beispiel #2
0
func (c *Client) AuthenticateWithPasscode(ctx scope.Context, room ManagedRoom, passcode string) (string, error) {
	mkey, err := room.MessageKey(ctx)
	if err != nil {
		return "", err
	}

	if mkey == nil {
		return "", nil
	}

	capability, err := mkey.PasscodeCapability(ctx, passcode)
	if err != nil {
		return "", err
	}

	if capability == nil {
		return "passcode incorrect", nil
	}

	holderKey := security.KeyFromPasscode([]byte(passcode), mkey.Nonce(), security.AES128)
	roomKey, err := decryptRoomKey(holderKey, capability)
	if err != nil {
		return "", err
	}

	// TODO: convert to account grant if signed in
	// TODO: load and return all historic keys

	c.Authorization.AddMessageKey(mkey.KeyID(), roomKey)
	c.Authorization.CurrentMessageKeyID = mkey.KeyID()
	return "", nil
}
Beispiel #3
0
func (gs *GrantManager) RevokeFromPasscode(ctx scope.Context, passcode string) error {
	cid, err := security.SharedSecretCapabilityID(
		security.KeyFromPasscode([]byte(passcode), gs.SubjectNonce, security.AES128),
		gs.SubjectNonce)
	if err != nil {
		return err
	}
	return gs.Capabilities.Remove(ctx, cid)
}
Beispiel #4
0
func TestNewAccountSecurity(t *testing.T) {
	kms := security.LocalKMS()
	kms.SetMasterKey(make([]byte, security.AES256.KeySize()))

	unlock := func(sec *AccountSecurity, password string) (*security.ManagedKeyPair, error) {
		return sec.Unlock(security.KeyFromPasscode([]byte(password), sec.Nonce, sec.UserKey.KeyType))
	}

	Convey("Encryption and decryption of generated keys", t, func() {
		sec, clientKey, err := NewAccountSecurity(kms, "hunter2")
		So(err, ShouldBeNil)
		So(sec.SystemKey.Encrypted(), ShouldBeTrue)
		So(sec.UserKey.Encrypted(), ShouldBeTrue)
		So(sec.KeyPair.Encrypted(), ShouldBeTrue)
		So(len(sec.Nonce), ShouldEqual, sec.KeyPair.NonceSize())
		So(clientKey.Encrypted(), ShouldBeFalse)

		kek := sec.SystemKey.Clone()
		So(kms.DecryptKey(&kek), ShouldBeNil)

		skp := sec.KeyPair.Clone()
		So(skp.Decrypt(&kek), ShouldBeNil)

		kp, err := unlock(sec, "")
		So(err, ShouldEqual, ErrAccessDenied)
		So(kp, ShouldBeNil)

		kp, err = unlock(sec, "hunter2")
		So(err, ShouldBeNil)
		So(kp.PrivateKey, ShouldResemble, skp.PrivateKey)
	})

	Convey("Password resets", t, func() {
		sec, _, err := NewAccountSecurity(kms, "hunter2")
		So(err, ShouldBeNil)

		nsec, err := sec.ResetPassword(kms, "hunter3")
		So(err, ShouldBeNil)

		skp, err := unlock(sec, "hunter2")
		So(err, ShouldBeNil)

		_, err = unlock(nsec, "hunter2")
		So(err, ShouldEqual, ErrAccessDenied)

		kp, err := unlock(nsec, "hunter3")
		So(err, ShouldBeNil)
		So(kp.PrivateKey, ShouldResemble, skp.PrivateKey)
	})
}
Beispiel #5
0
func (gs *GrantManager) GrantToPasscode(
	ctx scope.Context, manager Account, managerKey *security.ManagedKey, passcode string) error {

	_, public, private, err := gs.Authority(ctx, manager, managerKey)
	if err != nil {
		return err
	}

	c, err := security.GrantSharedSecretCapability(
		security.KeyFromPasscode([]byte(passcode), gs.SubjectNonce, security.AES128),
		gs.SubjectNonce, public, private)
	if err != nil {
		return err
	}

	return gs.Capabilities.Save(ctx, nil, c)
}
Beispiel #6
0
func (gs *GrantManager) PasscodeCapability(
	ctx scope.Context, passcode string) (*security.SharedSecretCapability, error) {

	cid, err := security.SharedSecretCapabilityID(
		security.KeyFromPasscode([]byte(passcode), gs.SubjectNonce, security.AES128),
		gs.SubjectNonce)
	if err != nil {
		return nil, err
	}

	c, err := gs.Capabilities.Get(ctx, cid)
	if err != nil {
		if err == ErrCapabilityNotFound {
			return nil, nil
		}
		return nil, err
	}
	return &security.SharedSecretCapability{Capability: c}, nil
}
Beispiel #7
0
func (a *memAccount) KeyFromPassword(password string) *security.ManagedKey {
	return security.KeyFromPasscode([]byte(password), a.sec.Nonce, a.sec.UserKey.KeyType)
}
Beispiel #8
0
func (ab *AccountBinding) KeyFromPassword(password string) *security.ManagedKey {
	return security.KeyFromPasscode([]byte(password), ab.Account.Nonce, proto.ClientKeyType)
}
Beispiel #9
0
// NewAccountSecurity initializes the nonce and account secrets for a new account
// with the given password. Returns an encrypted key-encrypting-key, encrypted
// key-pair, nonce, and error.
func NewAccountSecurity(
	kms security.KMS, password string) (*AccountSecurity, *security.ManagedKey, error) {

	kpType := security.Curve25519

	// Use one KMS request to obtain all the randomness we need:
	//   - nonce
	//   - private key
	randomData, err := kms.GenerateNonce(kpType.NonceSize() + kpType.PrivateKeySize())
	if err != nil {
		return nil, nil, fmt.Errorf("rng error: %s", err)
	}
	randomReader := bytes.NewReader(randomData)

	// Generate nonce with random data. Use to populate IV.
	nonce := make([]byte, kpType.NonceSize())
	if _, err := io.ReadFull(randomReader, nonce); err != nil {
		return nil, nil, fmt.Errorf("rng error: %s", err)
	}
	iv := make([]byte, ClientKeyType.BlockSize())
	copy(iv, nonce)

	// Generate key-encrypting-key using KMS. This will be returned encrypted,
	// using the base64 encoding of the nonce as its context.
	nonceBase64 := base64.URLEncoding.EncodeToString(nonce)
	systemKey, err := kms.GenerateEncryptedKey(ClientKeyType, "nonce", nonceBase64)
	if err != nil {
		return nil, nil, fmt.Errorf("key generation error: %s", err)
	}

	// Generate private key using randomReader.
	keyPair, err := kpType.Generate(randomReader)
	if err != nil {
		return nil, nil, fmt.Errorf("keypair generation error: %s", err)
	}

	// Decrypt key-encrypting-key so we can encrypt keypair, and so we can re-encrypt
	// it using the user's key.
	kek := systemKey.Clone()
	if err = kms.DecryptKey(&kek); err != nil {
		return nil, nil, fmt.Errorf("key decryption error: %s", err)
	}

	// Encrypt private key.
	keyPair.IV = iv
	if err = keyPair.Encrypt(&kek); err != nil {
		return nil, nil, fmt.Errorf("keypair encryption error: %s", err)
	}

	// Clone key-encrypting-key and encrypt with client key.
	clientKey := security.KeyFromPasscode([]byte(password), nonce, ClientKeyType)
	userKey := kek.Clone()
	userKey.IV = iv
	if err := userKey.Encrypt(clientKey); err != nil {
		return nil, nil, fmt.Errorf("key encryption error: %s", err)
	}

	// Generate message authentication code, for verifying passwords.
	var (
		mac [16]byte
		key [32]byte
	)
	copy(key[:], clientKey.Plaintext)
	poly1305.Sum(&mac, nonce, &key)

	sec := &AccountSecurity{
		Nonce:     nonce,
		MAC:       mac[:],
		SystemKey: *systemKey,
		UserKey:   userKey,
		KeyPair:   *keyPair,
	}
	return sec, clientKey, nil
}