예제 #1
0
파일: room.go 프로젝트: 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
}
예제 #2
0
파일: pm.go 프로젝트: 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
}
예제 #3
0
파일: etcd.go 프로젝트: robot0x/heim
func (e *etcdCluster) setSecret(kms security.KMS, name string, bytes int) ([]byte, error) {
	// Generate our own key.
	secret, err := kms.GenerateNonce(bytes)
	if err != nil {
		return nil, err
	}

	// Try to stake our claim on this secret.
	if _, err := e.c.Create(e.key("/secrets/%s", name), hex.EncodeToString(secret), 0); err != nil {
		if etcdErr, ok := err.(*etcd.EtcdError); ok && etcdErr.ErrorCode == 105 {
			// Lost the race, try to use GetSecret again.
			return e.GetSecret(kms, name, bytes)
		}
		return nil, err
	}

	return secret, nil
}
예제 #4
0
파일: room.go 프로젝트: 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
}
예제 #5
0
파일: account.go 프로젝트: NotAMoose/heim
func GeneratePasswordResetRequest(
	kms security.KMS, accountID snowflake.Snowflake) (*PasswordResetRequest, error) {

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

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

	now := time.Now()
	req := &PasswordResetRequest{
		ID:        id,
		AccountID: accountID,
		Key:       key,
		Requested: now,
		Expires:   now.Add(PasswordResetRequestLifetime),
	}
	return req, nil
}
예제 #6
0
파일: cluster.go 프로젝트: kennylixi/heim
func (tc *TestCluster) GetSecret(kms security.KMS, name string, bytes int) ([]byte, error) {
	tc.Lock()
	defer tc.Unlock()

	if secret, ok := tc.secrets[name]; ok {
		if len(secret) != bytes {
			return nil, fmt.Errorf("secret inconsistent: expected %d bytes, got %d", bytes, len(secret))
		}
		return secret, nil
	}

	secret, err := kms.GenerateNonce(bytes)
	if err != nil {
		return nil, err
	}

	if tc.secrets == nil {
		tc.secrets = map[string][]byte{name: secret}
	} else {
		tc.secrets[name] = secret
	}
	return secret, nil
}
예제 #7
0
파일: room.go 프로젝트: 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
}
예제 #8
0
파일: account.go 프로젝트: NotAMoose/heim
// 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
}
예제 #9
0
파일: account.go 프로젝트: logan/heim
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
}