encryption.go 1.7 KB

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