-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdecrypt.go
105 lines (89 loc) · 2.25 KB
/
decrypt.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
/*
* Copyright (c) 2019 Zenichi Amano
*
* This file is part of http-ece, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
package httpece
import (
"crypto/cipher"
"encoding/binary"
"fmt"
)
// Decrypt decrypts content data.
func Decrypt(content []byte, opts ...Option) ([]byte, error) {
var opt *options
var err error
// Options
if opt, err = parseOptions(decrypt, opts); err != nil {
return nil, err
}
content = readHeader(opt, content)
// Check Record Size
if opt.rs < sizeRecordMin || opt.rs > sizeRecordMax {
return nil, fmt.Errorf("invalid record size: %d", opt.rs)
}
debug.dumpBinary("sender public key", opt.dh)
debug.dumpBinary("receiver private key", opt.private)
// Derive key and nonce.
key, baseNonce, err := deriveKeyAndNonce(opt)
if err != nil {
return nil, err
}
gcm, err := createCipher(key)
if err != nil {
return nil, err
}
// Calculate chunkSize.
chunkSize := opt.rs
start := 0
counter := 0
contentLen := len(content)
if opt.encoding != AES128GCM {
chunkSize += gcm.Overhead()
}
// Decrypt records.
results := make([][]byte, (contentLen+chunkSize-1)/chunkSize)
for start < contentLen {
end := start + chunkSize
if end > contentLen {
end = contentLen
}
// Generate nonce.
nonce := generateNonce(baseNonce, counter)
debug.dumpBinary("nonce", nonce)
r, err := decryptRecord(opt, gcm, nonce, content[start:end])
if err != nil {
return nil, err
}
results = append(results, r)
debug.dumpBinary("result", r)
start = end
counter++
}
return resultsJoin(results), nil
}
func readHeader(opt *options, content []byte) []byte {
if opt.encoding == AES128GCM {
baseOffset := keyLen + 4
idLen := int(content[baseOffset])
opt.salt = content[0:keyLen]
opt.rs = int(binary.BigEndian.Uint32(content[keyLen:baseOffset]))
baseOffset++
opt.keyID = content[baseOffset : baseOffset+idLen]
return content[baseOffset+idLen:]
}
return content
}
func decryptRecord(opt *options, gcm cipher.AEAD, nonce []byte, content []byte) ([]byte, error) {
result, err := gcm.Open(nil, nonce, content, nil)
if err != nil {
return nil, err
}
switch opt.encoding {
case AESGCM:
return result[opt.encoding.Padding():], nil
default:
return result[:len(result)-opt.encoding.Padding()], nil
}
}