|
1 | 1 | package crypto |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "bytes" |
5 | | - "crypto/rand" |
6 | | - "crypto/rsa" |
7 | | - "crypto/sha256" |
8 | | - "crypto/x509" |
| 4 | + "crypto/hpke" |
| 5 | + "errors" |
9 | 6 | "slices" |
10 | | - |
11 | | - "github.com/torfstack/synod/backend/util" |
12 | 7 | ) |
13 | 8 |
|
14 | 9 | type AsymmetricCipher struct { |
15 | | - publicKey *rsa.PublicKey |
16 | | - privateKey *rsa.PrivateKey |
| 10 | + publicKey hpke.PublicKey |
| 11 | + privateKey hpke.PrivateKey |
17 | 12 | } |
18 | 13 |
|
| 14 | +var ( |
| 15 | + kem = hpke.MLKEM768X25519() |
| 16 | + kdf = hpke.HKDFSHA512() |
| 17 | + aead = hpke.AES256GCM() |
| 18 | +) |
| 19 | + |
19 | 20 | func (a *AsymmetricCipher) Encrypt(plaintext []byte) ([]byte, error) { |
20 | | - s, err := NewSymmetricCipher() |
21 | | - if err != nil { |
22 | | - return nil, err |
23 | | - } |
24 | | - encryptedSymmetricKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, a.publicKey, s.key, nil) |
25 | | - if err != nil { |
26 | | - return nil, err |
27 | | - } |
28 | | - ciphertext, err := s.Encrypt(plaintext) |
| 21 | + c, err := hpke.Seal(a.publicKey, kdf, aead, nil, plaintext) |
29 | 22 | if err != nil { |
30 | 23 | return nil, err |
31 | 24 | } |
32 | | - return slices.Concat( |
33 | | - MarkerBytes, RsaOaepMarkerBytes, |
34 | | - util.IntToBytes(uint32(len(encryptedSymmetricKey))), encryptedSymmetricKey, |
35 | | - util.IntToBytes(uint32(len(ciphertext))), ciphertext, |
36 | | - ), nil |
| 25 | + return slices.Concat(MarkerBytes, AsymmetricMarkerBytes, c), nil |
37 | 26 | } |
38 | 27 |
|
39 | 28 | func (a *AsymmetricCipher) Decrypt(ciphertext []byte) ([]byte, error) { |
40 | | - b := bytes.NewBuffer(ciphertext) |
41 | | - |
42 | | - marker := b.Next(4) |
43 | | - if !slices.Equal(marker, MarkerBytes) { |
44 | | - return nil, ErrCryptoInvalidMarker |
| 29 | + if len(ciphertext) < 9 { |
| 30 | + return nil, errors.New("ciphertext too short") |
45 | 31 | } |
46 | | - |
47 | | - algorithm := b.Next(4) |
48 | | - if !slices.Equal(algorithm, RsaOaepMarkerBytes) { |
49 | | - return nil, ErrCryptoAlgorithmMarker |
50 | | - } |
51 | | - |
52 | | - encryptedSymmetricKeyLen := util.BytesToInt(b.Next(4)) |
53 | | - encryptedSymmetricKey := b.Next(int(encryptedSymmetricKeyLen)) |
54 | | - |
55 | | - symmetricKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, a.privateKey, encryptedSymmetricKey, nil) |
56 | | - if err != nil { |
57 | | - return nil, err |
| 32 | + marker, algorithm := ciphertext[:4], ciphertext[4:8] |
| 33 | + if !slices.Equal(marker, MarkerBytes) || !slices.Equal(algorithm, AsymmetricMarkerBytes) { |
| 34 | + return nil, ErrCryptoInvalidMarker |
58 | 35 | } |
59 | | - s, err := SymmetricCipherFromKey(symmetricKey) |
| 36 | + p, err := hpke.Open(a.privateKey, kdf, aead, nil, ciphertext[8:]) |
60 | 37 | if err != nil { |
61 | 38 | return nil, err |
62 | 39 | } |
63 | | - |
64 | | - innerCiphertextLen := util.BytesToInt(b.Next(4)) |
65 | | - innerCiphertext := b.Next(int(innerCiphertextLen)) |
66 | | - |
67 | | - plaintext, err := s.Decrypt(innerCiphertext) |
68 | | - if err != nil { |
69 | | - return nil, err |
70 | | - } |
71 | | - return plaintext, nil |
| 40 | + return p, nil |
72 | 41 | } |
73 | 42 |
|
74 | 43 | func NewAsymmetricCipher() (*AsymmetricCipher, error) { |
75 | | - privateKey, err := rsa.GenerateKey(rand.Reader, RsaKeyLengthInBits) |
| 44 | + privateKey, err := hpke.MLKEM768X25519().GenerateKey() |
76 | 45 | if err != nil { |
77 | 46 | return nil, err |
78 | 47 | } |
79 | | - publicKey := privateKey.PublicKey |
| 48 | + publicKey := privateKey.PublicKey() |
80 | 49 | return &AsymmetricCipher{ |
81 | | - publicKey: &publicKey, |
| 50 | + publicKey: publicKey, |
82 | 51 | privateKey: privateKey, |
83 | 52 | }, nil |
84 | 53 | } |
85 | 54 |
|
86 | | -func AsymmetricCipherFromPublicKey(publicKey *rsa.PublicKey) (*AsymmetricCipher, error) { |
87 | | - return &AsymmetricCipher{ |
88 | | - publicKey: publicKey, |
89 | | - }, nil |
90 | | -} |
91 | | - |
92 | | -func AsymmetricCipherFromPrivateKey(privateKey *rsa.PrivateKey) (*AsymmetricCipher, error) { |
| 55 | +func AsymmetricCipherFromPrivateKey(privateKey hpke.PrivateKey) (*AsymmetricCipher, error) { |
93 | 56 | return &AsymmetricCipher{ |
94 | | - publicKey: privateKey.Public().(*rsa.PublicKey), |
| 57 | + publicKey: privateKey.PublicKey(), |
95 | 58 | privateKey: privateKey, |
96 | 59 | }, nil |
97 | 60 | } |
98 | 61 |
|
99 | | -func AsymmetricCipherFromPrivateKeyBytes(b []byte) (*AsymmetricCipher, error) { |
100 | | - priv, err := x509.ParsePKCS1PrivateKey(b) |
| 62 | +func AsymmetricCipherFromBytes(b []byte) (*AsymmetricCipher, error) { |
| 63 | + priv, err := kem.NewPrivateKey(b) |
101 | 64 | if err != nil { |
102 | 65 | return nil, err |
103 | 66 | } |
104 | | - priv.Precompute() |
105 | 67 | return AsymmetricCipherFromPrivateKey(priv) |
106 | 68 | } |
107 | 69 |
|
108 | 70 | func (a *AsymmetricCipher) Serialize() []byte { |
109 | | - return x509.MarshalPKCS1PrivateKey(a.privateKey) |
| 71 | + b, _ := a.privateKey.Bytes() |
| 72 | + return b |
110 | 73 | } |
0 commit comments