Esempio n. 1
0
File: room.go Progetto: logan/heim
func (r *memRoom) GenerateMessageKey(ctx scope.Context, kms security.KMS) (proto.RoomMessageKey, error) {
	nonce, err := kms.GenerateNonce(security.AES128.KeySize())
	if err != nil {
		return nil, err
	}

	mkey, err := kms.GenerateEncryptedKey(security.AES128, "room", r.name)
	if err != nil {
		return nil, err
	}

	kp := r.managerKey.KeyPair()
	r.messageKey = &roomMessageKey{
		GrantManager: &proto.GrantManager{
			Capabilities:     &capabilities{},
			Managers:         r.managerKey,
			KeyEncryptingKey: &r.sec.KeyEncryptingKey,
			SubjectKeyPair:   &kp,
			SubjectNonce:     nonce,
		},
		timestamp: time.Now(),
		nonce:     nonce,
		key:       *mkey,
	}
	r.messageKey.id = fmt.Sprintf("%s", r.messageKey.timestamp)
	return r.messageKey, nil
}
Esempio n. 2
0
File: pm.go Progetto: logan/heim
func NewPM(kms security.KMS, client *Client, initiatorNick string, receiver UserID, receiverNick string) (
	*PM, *security.ManagedKey, error) {

	if client.Account == nil {
		return nil, nil, ErrAccessDenied
	}

	pmID, err := snowflake.New()
	if err != nil {
		return nil, nil, err
	}

	iv, err := kms.GenerateNonce(RoomMessageKeyType.BlockSize())
	if err != nil {
		return nil, nil, err
	}

	encryptedSystemKey, err := kms.GenerateEncryptedKey(RoomMessageKeyType, "pm", pmID.String())
	if err != nil {
		return nil, nil, err
	}

	pmKey := encryptedSystemKey.Clone()
	if err := kms.DecryptKey(&pmKey); err != nil {
		return nil, nil, fmt.Errorf("pm key decrypt: %s", err)
	}
	//pmKey.IV = iv

	userKey := client.Account.UserKey()
	if err := userKey.Decrypt(client.Authorization.ClientKey); err != nil {
		return nil, nil, fmt.Errorf("initiator account key decrypt: %s", err)
	}

	encryptedInitiatorKey := pmKey.Clone()
	encryptedInitiatorKey.IV = iv
	if err := encryptedInitiatorKey.Encrypt(&userKey); err != nil {
		return nil, nil, fmt.Errorf("initiator pm key encrypt: %s", err)
	}

	var (
		mac [16]byte
		key [32]byte
	)
	copy(key[:], pmKey.Plaintext)
	poly1305.Sum(&mac, []byte(receiver), &key)

	pm := &PM{
		ID:                    pmID,
		Initiator:             client.Account.ID(),
		InitiatorNick:         initiatorNick,
		Receiver:              receiver,
		ReceiverNick:          receiverNick,
		ReceiverMAC:           mac[:],
		IV:                    iv,
		EncryptedSystemKey:    encryptedSystemKey,
		EncryptedInitiatorKey: &encryptedInitiatorKey,
	}
	return pm, &pmKey, nil
}
Esempio n. 3
0
File: room.go Progetto: logan/heim
func (r *Room) generateMessageKey(b *Backend, kms security.KMS) (*RoomMessageKeyBinding, error) {
	// Generate unique ID for storing new key in DB.
	keyID, err := snowflake.New()
	if err != nil {
		return nil, err
	}

	// Use KMS to generate nonce and key.
	nonce, err := kms.GenerateNonce(proto.RoomManagerKeyType.KeySize())
	if err != nil {
		return nil, err
	}

	mkey, err := kms.GenerateEncryptedKey(proto.RoomManagerKeyType, "room", r.Name)
	if err != nil {
		return nil, err
	}

	return NewRoomMessageKeyBinding(r.Bind(b), keyID, mkey, nonce), nil
}
Esempio n. 4
0
File: room.go Progetto: robot0x/heim
func NewRoomSecurity(kms security.KMS, roomName string) (*RoomSecurity, error) {
	kpType := security.Curve25519

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

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

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

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

	// Generate key-encrypting-key. This will be returned encrypted, using the
	// name of the room as its context.
	encryptedKek, err := kms.GenerateEncryptedKey(RoomManagerKeyType, "room", roomName)
	if err != nil {
		return nil, fmt.Errorf("key generation error: %s", err)
	}

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

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

	// Generate message authentication code, for verifying a given key-encryption-key.
	var (
		mac [16]byte
		key [32]byte
	)
	copy(key[:], kek.Plaintext)
	poly1305.Sum(&mac, iv, &key)

	sec := &RoomSecurity{
		Nonce:            nonce,
		MAC:              mac[:],
		KeyEncryptingKey: *encryptedKek,
		KeyPair:          *keyPair,
	}
	return sec, nil
}
Esempio n. 5
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
}
Esempio n. 6
0
func (b *AccountManagerBinding) GenerateOTP(ctx scope.Context, heim *proto.Heim, kms security.KMS, account proto.Account) (*proto.OTP, error) {
	encryptedKey, err := kms.GenerateEncryptedKey(OTPKeyType, "account", account.ID().String())
	if err != nil {
		return nil, err
	}

	key := encryptedKey.Clone()
	if err := kms.DecryptKey(&key); err != nil {
		return nil, err
	}

	iv, err := kms.GenerateNonce(OTPKeyType.BlockSize())
	if err != nil {
		return nil, err
	}

	t, err := b.DbMap.Begin()
	if err != nil {
		return nil, err
	}

	rawOTP, err := b.getRawOTP(t, account.ID())
	if err != nil && err != proto.ErrOTPNotEnrolled {
		rollback(ctx, t)
		return nil, err
	}
	if err == nil {
		if rawOTP.Validated {
			rollback(ctx, t)
			return nil, proto.ErrOTPAlreadyEnrolled
		}
		row := &OTP{AccountID: account.ID().String()}
		if _, err := t.Delete(row); err != nil {
			rollback(ctx, t)
			return nil, err
		}
	}

	otp, err := heim.NewOTP(account)
	if err != nil {
		rollback(ctx, t)
		return nil, err
	}

	digest, encryptedURI, err := security.EncryptGCM(&key, iv, []byte(otp.URI), nil)
	if err != nil {
		rollback(ctx, t)
		return nil, err
	}

	row := &OTP{
		AccountID:    account.ID().String(),
		IV:           iv,
		EncryptedKey: encryptedKey.Ciphertext,
		Digest:       digest,
		EncryptedURI: encryptedURI,
	}
	if err := t.Insert(row); err != nil {
		// TODO: this could fail in the case of a race condition
		// by the time that matters we should be on postgres 9.5 and using a proper upsert
		rollback(ctx, t)
		return nil, err
	}

	if err := t.Commit(); err != nil {
		return nil, err
	}

	return otp, nil
}