-
Notifications
You must be signed in to change notification settings - Fork 0
/
encrypters.go
130 lines (116 loc) · 3.31 KB
/
encrypters.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package encryptedbox
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"errors"
"fmt"
"hash"
"io"
"github.com/jswidler/encryptedbox/rsautil"
)
// AES will return a symmetric Encrypter using AES
func AES(key []byte) (Encrypter, error) {
l := len(key)
if l != 32 && l != 24 && l != 16 {
return nil, errors.New("AES keys must be 16, 24, or 32 bytes")
}
return &aesEnc{key}, nil
}
// RSA will return an asymmetric Encrypter using RSA
func RSA(privateKeyPem []byte) (Encrypter, error) {
key, err := rsautil.PemToPrivateKey(privateKeyPem)
if err != nil {
return nil, fmt.Errorf("failed to read RSA private key: %w", err)
}
return rsaEnc{privateKey: key, publicKey: &key.PublicKey}, nil
}
// RSAEncryptOnly will return an asymmetric Encrypter using RSA
// which can only Encrypt.
func RSAEncryptOnly(publicKeyPem []byte) (Encrypter, error) {
key, err := rsautil.PemToPublicKey(publicKeyPem)
if err != nil {
return nil, fmt.Errorf("failed to read RSA public key: %w", err)
}
return rsaEnc{publicKey: key}, nil
}
type aesEnc struct {
key []byte
}
func (a aesEnc) Encrypt(plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
aead, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, aead.NonceSize())
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
return nil, err
}
return aead.Seal(nonce[:], nonce[:], plaintext, nil), nil
}
func (a aesEnc) Decrypt(ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
aead, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := aead.NonceSize()
if len(ciphertext) < nonceSize {
return nil, errors.New("invalid ciphertext")
}
return aead.Open(nil, ciphertext[:nonceSize], ciphertext[nonceSize:], nil)
}
type rsaEnc struct {
privateKey *rsa.PrivateKey
publicKey *rsa.PublicKey
}
func (r rsaEnc) Encrypt(plaintext []byte) ([]byte, error) {
return encryptOAEPChunks(sha512.New(), rand.Reader, r.publicKey, plaintext, nil)
}
func (r rsaEnc) Decrypt(ciphertext []byte) ([]byte, error) {
return decryptOAEPChunks(sha512.New(), nil, r.privateKey, ciphertext, nil)
}
func encryptOAEPChunks(hash hash.Hash, random io.Reader, public *rsa.PublicKey, msg []byte, label []byte) ([]byte, error) {
msgLen := len(msg)
step := public.Size() - 2*hash.Size() - 2
var encryptedBytes []byte
for start := 0; start < msgLen; start += step {
finish := start + step
if finish > msgLen {
finish = msgLen
}
encryptedBlockBytes, err := rsa.EncryptOAEP(hash, random, public, msg[start:finish], label)
if err != nil {
return nil, err
}
encryptedBytes = append(encryptedBytes, encryptedBlockBytes...)
}
return encryptedBytes, nil
}
func decryptOAEPChunks(hash hash.Hash, random io.Reader, private *rsa.PrivateKey, msg []byte, label []byte) ([]byte, error) {
msgLen := len(msg)
step := private.PublicKey.Size()
var decryptedBytes []byte
for start := 0; start < msgLen; start += step {
finish := start + step
if finish > msgLen {
finish = msgLen
}
decryptedBlockBytes, err := rsa.DecryptOAEP(hash, random, private, msg[start:finish], label)
if err != nil {
return nil, err
}
decryptedBytes = append(decryptedBytes, decryptedBlockBytes...)
}
return decryptedBytes, nil
}