]> Cypherpunks.ru repositories - nncp.git/blob - src/eblob.go
8bf2e978fd4895df548625530906b4e0c6c080cc
[nncp.git] / src / eblob.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package nncp
19
20 import (
21         "bytes"
22         "crypto/rand"
23         "hash"
24
25         xdr "github.com/davecgh/go-xdr/xdr2"
26         "go.cypherpunks.ru/balloon"
27         "golang.org/x/crypto/blake2b"
28         "golang.org/x/crypto/chacha20poly1305"
29 )
30
31 const (
32         DefaultS = 1 << 20 / 32
33         DefaultT = 1 << 4
34         DefaultP = 2
35 )
36
37 type EBlob struct {
38         Magic [8]byte
39         SCost uint32
40         TCost uint32
41         PCost uint32
42         Salt  *[32]byte
43         Blob  []byte
44 }
45
46 func blake256() hash.Hash {
47         h, err := blake2b.New256(nil)
48         if err != nil {
49                 panic(err)
50         }
51         return h
52 }
53
54 // Create an encrypted blob. sCost -- memory space requirements, number
55 // of hash-output sized (32 bytes) blocks. tCost -- time requirements,
56 // number of rounds. pCost -- number of parallel jobs.
57 func NewEBlob(sCost, tCost, pCost int, password, data []byte) ([]byte, error) {
58         salt := new([32]byte)
59         var err error
60         if _, err = rand.Read(salt[:]); err != nil {
61                 return nil, err
62         }
63         eblob := EBlob{
64                 Magic: MagicNNCPBv3.B,
65                 SCost: uint32(sCost),
66                 TCost: uint32(tCost),
67                 PCost: uint32(pCost),
68                 Salt:  salt,
69                 Blob:  nil,
70         }
71         var eblobBuf bytes.Buffer
72         if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
73                 return nil, err
74         }
75         key := balloon.H(blake256, password, salt[:], sCost, tCost, pCost)
76         aead, err := chacha20poly1305.New(key)
77         if err != nil {
78                 return nil, err
79         }
80         buf := make([]byte, 0, len(data)+aead.Overhead())
81         buf = aead.Seal(buf, make([]byte, aead.NonceSize()), data, eblobBuf.Bytes())
82         eblob.Blob = buf
83         eblobBuf.Reset()
84         if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
85                 return nil, err
86         }
87         return eblobBuf.Bytes(), nil
88 }
89
90 func DeEBlob(eblobRaw, password []byte) ([]byte, error) {
91         var eblob EBlob
92         var err error
93         if _, err = xdr.Unmarshal(bytes.NewReader(eblobRaw), &eblob); err != nil {
94                 return nil, err
95         }
96         switch eblob.Magic {
97         case MagicNNCPBv1.B:
98                 err = MagicNNCPBv1.TooOld()
99         case MagicNNCPBv2.B:
100                 err = MagicNNCPBv1.TooOld()
101         case MagicNNCPBv3.B:
102         default:
103                 err = BadMagic
104         }
105         if err != nil {
106                 return nil, err
107         }
108         key := balloon.H(
109                 blake256,
110                 password,
111                 eblob.Salt[:],
112                 int(eblob.SCost),
113                 int(eblob.TCost),
114                 int(eblob.PCost),
115         )
116         aead, err := chacha20poly1305.New(key)
117         if err != nil {
118                 return nil, err
119         }
120
121         ciphertext := eblob.Blob
122         eblob.Blob = nil
123         var eblobBuf bytes.Buffer
124         if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
125                 return nil, err
126         }
127         data, err := aead.Open(
128                 ciphertext[:0],
129                 make([]byte, aead.NonceSize()),
130                 ciphertext,
131                 eblobBuf.Bytes(),
132         )
133         if err != nil {
134                 return nil, err
135         }
136         return data, nil
137 }