xref: /aosp_15_r20/external/tink/go/hybrid/hpke_private_key_manager.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17package hybrid
18
19import (
20	"errors"
21	"fmt"
22
23	"google.golang.org/protobuf/proto"
24	"github.com/google/tink/go/core/registry"
25	"github.com/google/tink/go/hybrid/internal/hpke"
26	"github.com/google/tink/go/keyset"
27	"github.com/google/tink/go/subtle"
28	hpkepb "github.com/google/tink/go/proto/hpke_go_proto"
29	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
30)
31
32const (
33	// maxSupportedHPKEPrivateKeyVersion is the max supported private key
34	// version. It must be incremented when support for new versions are
35	// implemented.
36	maxSupportedHPKEPrivateKeyVersion uint32 = 0
37	hpkePrivateKeyTypeURL                    = "type.googleapis.com/google.crypto.tink.HpkePrivateKey"
38)
39
40var (
41	errInvalidHPKEPrivateKey       = errors.New("invalid HPKE private key")
42	errInvalidHPKEPrivateKeyFormat = errors.New("invalid HPKE private key format")
43)
44
45// hpkePrivateKeyManager implements the KeyManager interface for HybridDecrypt.
46type hpkePrivateKeyManager struct{}
47
48var _ registry.PrivateKeyManager = (*hpkePrivateKeyManager)(nil)
49
50func (p *hpkePrivateKeyManager) Primitive(serializedKey []byte) (interface{}, error) {
51	if len(serializedKey) == 0 {
52		return nil, errInvalidHPKEPrivateKey
53	}
54	key := new(hpkepb.HpkePrivateKey)
55	if err := proto.Unmarshal(serializedKey, key); err != nil {
56		return nil, errInvalidHPKEPrivateKey
57	}
58	if err := keyset.ValidateKeyVersion(key.GetVersion(), maxSupportedHPKEPrivateKeyVersion); err != nil {
59		return nil, err
60	}
61	return hpke.NewDecrypt(key)
62}
63
64// NewKey returns a set of private and public keys of key version 0.
65func (p *hpkePrivateKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) {
66	if len(serializedKeyFormat) == 0 {
67		return nil, errInvalidHPKEPrivateKeyFormat
68	}
69	keyFormat := new(hpkepb.HpkeKeyFormat)
70	if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil {
71		return nil, errInvalidHPKEPrivateKeyFormat
72	}
73	if err := validateKeyFormat(keyFormat); err != nil {
74		return nil, err
75	}
76
77	privKeyBytes, err := subtle.GeneratePrivateKeyX25519()
78	if err != nil {
79		return nil, fmt.Errorf("generate X25519 private key: %v", err)
80	}
81	pubKeyBytes, err := subtle.PublicFromPrivateX25519(privKeyBytes)
82	if err != nil {
83		return nil, fmt.Errorf("get X25519 public key from private key: %v", err)
84	}
85
86	return &hpkepb.HpkePrivateKey{
87		Version: 0,
88		PublicKey: &hpkepb.HpkePublicKey{
89			Version:   0,
90			Params:    keyFormat.GetParams(),
91			PublicKey: pubKeyBytes,
92		},
93		PrivateKey: privKeyBytes,
94	}, nil
95}
96
97func (p *hpkePrivateKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) {
98	key, err := p.NewKey(serializedKeyFormat)
99	if err != nil {
100		return nil, err
101	}
102	serializedKey, err := proto.Marshal(key)
103	if err != nil {
104		return nil, err
105	}
106	return &tinkpb.KeyData{
107		TypeUrl:         hpkePrivateKeyTypeURL,
108		Value:           serializedKey,
109		KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE,
110	}, nil
111}
112
113func (p *hpkePrivateKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) {
114	privKey := new(hpkepb.HpkePrivateKey)
115	if err := proto.Unmarshal(serializedPrivKey, privKey); err != nil {
116		return nil, errInvalidHPKEPrivateKey
117	}
118	serializedPubKey, err := proto.Marshal(privKey.GetPublicKey())
119	if err != nil {
120		return nil, errInvalidHPKEPrivateKey
121	}
122	return &tinkpb.KeyData{
123		TypeUrl:         hpkePublicKeyTypeURL,
124		Value:           serializedPubKey,
125		KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC,
126	}, nil
127}
128
129func (p *hpkePrivateKeyManager) DoesSupport(typeURL string) bool {
130	return typeURL == hpkePrivateKeyTypeURL
131}
132
133func (p *hpkePrivateKeyManager) TypeURL() string {
134	return hpkePrivateKeyTypeURL
135}
136
137func validateKeyFormat(kf *hpkepb.HpkeKeyFormat) error {
138	params := kf.GetParams()
139	kem, kdf, aead := params.GetKem(), params.GetKdf(), params.GetAead()
140	if kem != hpkepb.HpkeKem_DHKEM_X25519_HKDF_SHA256 ||
141		kdf != hpkepb.HpkeKdf_HKDF_SHA256 ||
142		(aead != hpkepb.HpkeAead_AES_128_GCM && aead != hpkepb.HpkeAead_AES_256_GCM && aead != hpkepb.HpkeAead_CHACHA20_POLY1305) {
143		return errInvalidHPKEPrivateKeyFormat
144	}
145	return nil
146}
147