encryption.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. package util
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/rand"
  6. "crypto/sha256"
  7. "errors"
  8. "io"
  9. )
  10. const saltLength = 8
  11. // Decrypt decrypts a payload with a given secret.
  12. func Decrypt(payload []byte, secret string) ([]byte, error) {
  13. salt := payload[:saltLength]
  14. key := encryptionKeyToBytes(secret, string(salt))
  15. block, err := aes.NewCipher(key)
  16. if err != nil {
  17. return nil, err
  18. }
  19. // The IV needs to be unique, but not secure. Therefore it's common to
  20. // include it at the beginning of the ciphertext.
  21. if len(payload) < aes.BlockSize {
  22. return nil, errors.New("payload too short")
  23. }
  24. iv := payload[saltLength : saltLength+aes.BlockSize]
  25. payload = payload[saltLength+aes.BlockSize:]
  26. payloadDst := make([]byte, len(payload))
  27. stream := cipher.NewCFBDecrypter(block, iv)
  28. // XORKeyStream can work in-place if the two arguments are the same.
  29. stream.XORKeyStream(payloadDst, payload)
  30. return payloadDst, nil
  31. }
  32. // Encrypt encrypts a payload with a given secret.
  33. func Encrypt(payload []byte, secret string) ([]byte, error) {
  34. salt := GetRandomString(saltLength)
  35. key := encryptionKeyToBytes(secret, salt)
  36. block, err := aes.NewCipher(key)
  37. if err != nil {
  38. return nil, err
  39. }
  40. // The IV needs to be unique, but not secure. Therefore it's common to
  41. // include it at the beginning of the ciphertext.
  42. ciphertext := make([]byte, saltLength+aes.BlockSize+len(payload))
  43. copy(ciphertext[:saltLength], []byte(salt))
  44. iv := ciphertext[saltLength : saltLength+aes.BlockSize]
  45. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  46. return nil, err
  47. }
  48. stream := cipher.NewCFBEncrypter(block, iv)
  49. stream.XORKeyStream(ciphertext[saltLength+aes.BlockSize:], payload)
  50. return ciphertext, nil
  51. }
  52. // Key needs to be 32bytes
  53. func encryptionKeyToBytes(secret, salt string) []byte {
  54. return PBKDF2([]byte(secret), []byte(salt), 10000, 32, sha256.New)
  55. }