]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/eblob.go
Forbid any later GNU GPL versions autousage
[nncp.git] / src / cypherpunks.ru / nncp / eblob.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2019 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         "cypherpunks.ru/balloon"
26         "github.com/davecgh/go-xdr/xdr2"
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 var (
38         MagicNNCPBv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'B', 0, 0, 3}
39 )
40
41 type EBlob struct {
42         Magic [8]byte
43         SCost uint32
44         TCost uint32
45         PCost uint32
46         Salt  *[32]byte
47         Blob  []byte
48 }
49
50 func blake256() hash.Hash {
51         h, err := blake2b.New256(nil)
52         if err != nil {
53                 panic(err)
54         }
55         return h
56 }
57
58 // Create an encrypted blob. sCost -- memory space requirements, number
59 // of hash-output sized (32 bytes) blocks. tCost -- time requirements,
60 // number of rounds. pCost -- number of parallel jobs.
61 func NewEBlob(sCost, tCost, pCost int, password, data []byte) ([]byte, error) {
62         salt := new([32]byte)
63         var err error
64         if _, err = rand.Read(salt[:]); err != nil {
65                 return nil, err
66         }
67         eblob := EBlob{
68                 Magic: MagicNNCPBv3,
69                 SCost: uint32(sCost),
70                 TCost: uint32(tCost),
71                 PCost: uint32(pCost),
72                 Salt:  salt,
73                 Blob:  nil,
74         }
75         var eblobBuf bytes.Buffer
76         if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
77                 return nil, err
78         }
79         key := balloon.H(blake256, password, salt[:], sCost, tCost, pCost)
80         aead, err := chacha20poly1305.New(key)
81         if err != nil {
82                 return nil, err
83         }
84         buf := make([]byte, 0, len(data)+aead.Overhead())
85         buf = aead.Seal(buf, make([]byte, aead.NonceSize()), data, eblobBuf.Bytes())
86         eblob.Blob = buf
87         eblobBuf.Reset()
88         if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
89                 return nil, err
90         }
91         return eblobBuf.Bytes(), nil
92 }
93
94 func DeEBlob(eblobRaw, password []byte) ([]byte, error) {
95         var eblob EBlob
96         var err error
97         if _, err = xdr.Unmarshal(bytes.NewReader(eblobRaw), &eblob); err != nil {
98                 return nil, err
99         }
100         if eblob.Magic != MagicNNCPBv3 {
101                 return nil, BadMagic
102         }
103         key := balloon.H(
104                 blake256,
105                 password,
106                 eblob.Salt[:],
107                 int(eblob.SCost),
108                 int(eblob.TCost),
109                 int(eblob.PCost),
110         )
111         aead, err := chacha20poly1305.New(key)
112         if err != nil {
113                 return nil, err
114         }
115
116         ciphertext := eblob.Blob
117         eblob.Blob = nil
118         var eblobBuf bytes.Buffer
119         if _, err = xdr.Marshal(&eblobBuf, &eblob); err != nil {
120                 return nil, err
121         }
122         data, err := aead.Open(
123                 ciphertext[:0],
124                 make([]byte, aead.NonceSize()),
125                 ciphertext,
126                 eblobBuf.Bytes(),
127         )
128         if err != nil {
129                 return nil, err
130         }
131         return data, nil
132 }