nacl.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package encryption
  2. import (
  3. cryptorand "crypto/rand"
  4. "fmt"
  5. "io"
  6. "github.com/docker/swarmkit/api"
  7. "golang.org/x/crypto/nacl/secretbox"
  8. )
  9. const naclSecretboxKeySize = 32
  10. const naclSecretboxNonceSize = 24
  11. // This provides the default implementation of an encrypter and decrypter, as well
  12. // as the default KDF function.
  13. // NACLSecretbox is an implementation of an encrypter/decrypter. Encrypting
  14. // generates random Nonces.
  15. type NACLSecretbox struct {
  16. key [naclSecretboxKeySize]byte
  17. }
  18. // NewNACLSecretbox returns a new NACL secretbox encrypter/decrypter with the given key
  19. func NewNACLSecretbox(key []byte) NACLSecretbox {
  20. secretbox := NACLSecretbox{}
  21. copy(secretbox.key[:], key)
  22. return secretbox
  23. }
  24. // Algorithm returns the type of algorithm this is (NACL Secretbox using XSalsa20 and Poly1305)
  25. func (n NACLSecretbox) Algorithm() api.MaybeEncryptedRecord_Algorithm {
  26. return api.MaybeEncryptedRecord_NACLSecretboxSalsa20Poly1305
  27. }
  28. // Encrypt encrypts some bytes and returns an encrypted record
  29. func (n NACLSecretbox) Encrypt(data []byte) (*api.MaybeEncryptedRecord, error) {
  30. var nonce [24]byte
  31. if _, err := io.ReadFull(cryptorand.Reader, nonce[:]); err != nil {
  32. return nil, err
  33. }
  34. // Seal's first argument is an "out", the data that the new encrypted message should be
  35. // appended to. Since we don't want to append anything, we pass nil.
  36. encrypted := secretbox.Seal(nil, data, &nonce, &n.key)
  37. return &api.MaybeEncryptedRecord{
  38. Algorithm: n.Algorithm(),
  39. Data: encrypted,
  40. Nonce: nonce[:],
  41. }, nil
  42. }
  43. // Decrypt decrypts a MaybeEncryptedRecord and returns some bytes
  44. func (n NACLSecretbox) Decrypt(record api.MaybeEncryptedRecord) ([]byte, error) {
  45. if record.Algorithm != n.Algorithm() {
  46. return nil, fmt.Errorf("not a NACL secretbox record")
  47. }
  48. if len(record.Nonce) != naclSecretboxNonceSize {
  49. return nil, fmt.Errorf("invalid nonce size for NACL secretbox: require 24, got %d", len(record.Nonce))
  50. }
  51. var decryptNonce [naclSecretboxNonceSize]byte
  52. copy(decryptNonce[:], record.Nonce[:naclSecretboxNonceSize])
  53. // Open's first argument is an "out", the data that the decrypted message should be
  54. // appended to. Since we don't want to append anything, we pass nil.
  55. decrypted, ok := secretbox.Open(nil, record.Data, &decryptNonce, &n.key)
  56. if !ok {
  57. return nil, fmt.Errorf("decryption error using NACL secretbox")
  58. }
  59. return decrypted, nil
  60. }