encryption.go 1.7 KB

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