1/* 2NNCP -- Node to Node copy, utilities for store-and-forward data exchange 3Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org> 4 5This program is free software: you can redistribute it and/or modify 6it under the terms of the GNU General Public License as published by 7the Free Software Foundation, version 3 of the License. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with this program. If not, see <http://www.gnu.org/licenses/>. 16*/ 17 18package nncp 19 20import ( 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 31const ( 32 DefaultS = 1 << 20 / 32 33 DefaultT = 1 << 4 34 DefaultP = 2 35) 36 37type EBlob struct { 38 Magic [8]byte 39 SCost uint32 40 TCost uint32 41 PCost uint32 42 Salt *[32]byte 43 Blob []byte 44} 45 46func 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. 57func 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 90func 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} 138