github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/helpers/crypto/box.go (about) 1 package crypto 2 3 import ( 4 "crypto/rand" 5 "errors" 6 7 "code.google.com/p/go.crypto/nacl/secretbox" 8 ) 9 10 const ( 11 // EncryptionKeySize is the keySize which is used to encrypt data. 12 EncryptionKeySize = 32 13 14 // secretbox nonceSize 15 nonceSize = 24 16 17 // pre-computed minimal length of ciphertext; anything less cannot be valid 18 // and will be rejected before attempting any other operations. 19 encryptedContentMinSize = 2*(nonceSize+secretbox.Overhead) + EncryptionKeySize 20 ) 21 22 // Box encapsulates the encryption and decryption of files with a given 23 // Encryption key. 24 type Box struct { 25 privateKey [EncryptionKeySize]byte 26 } 27 28 // NewBox initializes a Box with the passed encryption key, which can be used 29 // to encrypt and decrypt data. 30 func NewBox(privateKey [EncryptionKeySize]byte) *Box { 31 return &Box{ 32 privateKey: privateKey, 33 } 34 } 35 36 // EncryptWithRandomKey takes a piece of data, encrypts it with a random 37 // key and returns the result, prefixed by the random key encrypted by 38 // the repository encryption key. 39 func (b *Box) EncryptWithRandomKey(data []byte) ([]byte, error) { 40 // first generate and encrypt the per-file key and append it to 41 // the result buffer: 42 var nonce1 [nonceSize]byte 43 _, err := rand.Read(nonce1[:]) 44 if err != nil { 45 return nil, err 46 } 47 48 var fileKey [32]byte 49 _, err = rand.Read(fileKey[:]) 50 if err != nil { 51 return nil, err 52 } 53 54 encryptionKey := b.privateKey 55 out := nonce1[:] 56 out = secretbox.Seal(out, fileKey[:], &nonce1, &encryptionKey) 57 58 // then append the actual encrypted contents 59 var nonce2 [nonceSize]byte 60 _, err = rand.Read(nonce2[:]) 61 if err != nil { 62 return nil, err 63 } 64 out = append(out, nonce2[:]...) 65 out = secretbox.Seal(out, data, &nonce2, &fileKey) 66 return out, nil 67 } 68 69 // DecryptContent is the counter-part of EncryptWithRandomKey, i.e. 70 // it returns the plain text again. 71 func (b *Box) DecryptContent(enc []byte) ([]byte, error) { 72 if len(enc) < encryptedContentMinSize { 73 return nil, errors.New("truncated ciphertext") 74 } 75 76 // first decrypt the file-specific key using the master key 77 var nonce [nonceSize]byte 78 readNonce := func() { 79 copy(nonce[:], enc[:nonceSize]) 80 enc = enc[nonceSize:] 81 } 82 readNonce() 83 encryptionKey := b.privateKey 84 85 l := EncryptionKeySize + secretbox.Overhead 86 encryptedFileKey := enc[:l] 87 enc = enc[l:] 88 var fileKey []byte 89 fileKey, success := secretbox.Open(fileKey, encryptedFileKey, &nonce, &encryptionKey) 90 if !success { 91 return nil, errors.New("file key decryption failed") 92 } 93 94 var arrFileKey [EncryptionKeySize]byte 95 copy(arrFileKey[:], fileKey) 96 97 readNonce() 98 var content []byte 99 content, success = secretbox.Open(content, enc, &nonce, &arrFileKey) 100 if !success { 101 return nil, errors.New("content decryption failed") 102 } 103 104 return content, nil 105 }