shortkem.go raw
1 package hpke
2
3 import (
4 "crypto/ecdh"
5 "crypto/rand"
6 "fmt"
7
8 "github.com/cloudflare/circl/kem"
9 )
10
11 type shortKEM struct {
12 dhKemBase
13 ecdh.Curve
14 }
15
16 func (s shortKEM) PrivateKeySize() int { return s.byteSize() }
17 func (s shortKEM) SeedSize() int { return s.byteSize() }
18 func (s shortKEM) CiphertextSize() int { return 1 + 2*s.byteSize() }
19 func (s shortKEM) PublicKeySize() int { return 1 + 2*s.byteSize() }
20 func (s shortKEM) EncapsulationSeedSize() int { return s.byteSize() }
21
22 func (s shortKEM) byteSize() int {
23 var bits int
24 switch s.Curve {
25 case ecdh.P256():
26 bits = 256
27 case ecdh.P384():
28 bits = 384
29 case ecdh.P521():
30 bits = 521
31 default:
32 panic(ErrInvalidKEM)
33 }
34
35 return (bits + 7) / 8
36 }
37
38 func (s shortKEM) sizeDH() int { return s.byteSize() }
39 func (s shortKEM) calcDH(dh []byte, sk kem.PrivateKey, pk kem.PublicKey) error {
40 PK, ok := pk.(*shortKEMPubKey)
41 if !ok {
42 return ErrInvalidKEMPublicKey
43 }
44
45 SK, ok := sk.(*shortKEMPrivKey)
46 if !ok {
47 return ErrInvalidKEMPrivateKey
48 }
49
50 x, err := SK.priv.ECDH(&PK.pub)
51 if err != nil {
52 return err
53 }
54
55 copy(dh, x)
56 return nil
57 }
58
59 // Deterministically derives a keypair from a seed. If you're unsure,
60 // you're better off using GenerateKey().
61 //
62 // Panics if seed is not of length SeedSize().
63 func (s shortKEM) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) {
64 // Implementation based on
65 // https://www.ietf.org/archive/id/draft-irtf-cfrg-hpke-07.html#name-derivekeypair
66 if len(seed) != s.SeedSize() {
67 panic(kem.ErrSeedSize)
68 }
69
70 bitmask := byte(0xFF)
71 if s.Curve == ecdh.P521() {
72 bitmask = 0x01
73 }
74
75 dkpPrk := s.labeledExtract([]byte(""), []byte("dkp_prk"), seed)
76 for ctr := 0; ctr <= 255; ctr++ {
77 bytes := s.labeledExpand(
78 dkpPrk,
79 []byte("candidate"),
80 []byte{byte(ctr)},
81 uint16(s.byteSize()),
82 )
83 bytes[0] &= bitmask
84 sk, err := s.UnmarshalBinaryPrivateKey(bytes)
85 if err == nil {
86 return sk.Public(), sk
87 }
88 }
89
90 panic(ErrInvalidKEMDeriveKey)
91 }
92
93 func (s shortKEM) GenerateKeyPair() (kem.PublicKey, kem.PrivateKey, error) {
94 key, err := s.Curve.GenerateKey(rand.Reader)
95 if err != nil {
96 return nil, nil, err
97 }
98
99 sk := &shortKEMPrivKey{s, key}
100 return sk.Public(), sk, err
101 }
102
103 func (s shortKEM) UnmarshalBinaryPrivateKey(data []byte) (kem.PrivateKey, error) {
104 key, err := s.Curve.NewPrivateKey(data)
105 if err != nil {
106 return nil, ErrInvalidKEMPrivateKey
107 }
108
109 return &shortKEMPrivKey{s, key}, nil
110 }
111
112 func (s shortKEM) UnmarshalBinaryPublicKey(data []byte) (kem.PublicKey, error) {
113 key, err := s.Curve.NewPublicKey(data)
114 if err != nil {
115 return nil, ErrInvalidKEMPublicKey
116 }
117
118 return &shortKEMPubKey{s, *key}, nil
119 }
120
121 type shortKEMPubKey struct {
122 scheme shortKEM
123 pub ecdh.PublicKey
124 }
125
126 func (k *shortKEMPubKey) String() string { return fmt.Sprintf("%x", k.pub.Bytes()) }
127 func (k *shortKEMPubKey) Scheme() kem.Scheme { return k.scheme }
128 func (k *shortKEMPubKey) MarshalBinary() ([]byte, error) { return k.pub.Bytes(), nil }
129
130 func (k *shortKEMPubKey) Equal(pk kem.PublicKey) bool {
131 k1, ok := pk.(*shortKEMPubKey)
132 return ok && k.scheme == k1.scheme && k.pub.Equal(&k1.pub)
133 }
134
135 type shortKEMPrivKey struct {
136 scheme shortKEM
137 priv *ecdh.PrivateKey
138 }
139
140 func (k *shortKEMPrivKey) String() string { return fmt.Sprintf("%x", k.priv.Bytes()) }
141 func (k *shortKEMPrivKey) Scheme() kem.Scheme { return k.scheme }
142 func (k *shortKEMPrivKey) MarshalBinary() ([]byte, error) { return k.priv.Bytes(), nil }
143
144 func (k *shortKEMPrivKey) Equal(pk kem.PrivateKey) bool {
145 k1, ok := pk.(*shortKEMPrivKey)
146 return ok && k.scheme == k1.scheme && k.priv.Equal(k1.priv)
147 }
148
149 func (k *shortKEMPrivKey) Public() kem.PublicKey {
150 return &shortKEMPubKey{k.scheme, *k.priv.PublicKey()}
151 }
152