Core components of the web application. https://write.as
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
1.7 KiB

  1. // Package data provides utilities for interacting with database data
  2. // throughout Write.as.
  3. package data
  4. import (
  5. "crypto/aes"
  6. "crypto/cipher"
  7. "crypto/rand"
  8. "errors"
  9. "fmt"
  10. )
  11. // Encryption parameters
  12. const (
  13. keyLen = 32
  14. delimiter = '%'
  15. )
  16. // Encrypt AES-encrypts given text with the given key k.
  17. // This is used for encrypting sensitive information in the database, such as
  18. // oAuth tokens and email addresses.
  19. func Encrypt(k []byte, text string) ([]byte, error) {
  20. // Validate parameters
  21. if len(k) != keyLen {
  22. return nil, errors.New(fmt.Sprintf("Invalid key length (must be %d bytes).", keyLen))
  23. }
  24. // Encrypt plaintext with AES-GCM
  25. block, err := aes.NewCipher(k)
  26. if err != nil {
  27. return nil, err
  28. }
  29. gcm, err := cipher.NewGCM(block)
  30. if err != nil {
  31. return nil, err
  32. }
  33. // Generate nonce
  34. ns := gcm.NonceSize()
  35. nonce := make([]byte, ns)
  36. if _, err := rand.Read(nonce); err != nil {
  37. return nil, err
  38. }
  39. ciphertext := gcm.Seal(nil, nonce, []byte(text), nil)
  40. // Build text output in the format:
  41. // NonceCiphertext
  42. outtext := append(nonce, ciphertext...)
  43. return outtext, nil
  44. }
  45. // Decrypt decrypts the given ciphertext with the given key k.
  46. func Decrypt(k, ciphertext []byte) ([]byte, error) {
  47. // Decrypt ciphertext
  48. block, err := aes.NewCipher(k)
  49. if err != nil {
  50. return nil, err
  51. }
  52. gcm, err := cipher.NewGCM(block)
  53. if err != nil {
  54. return nil, err
  55. }
  56. ns := gcm.NonceSize()
  57. // Validate data
  58. if len(ciphertext) < ns {
  59. return nil, errors.New("Ciphertext is too short")
  60. }
  61. nonce := ciphertext[:ns]
  62. ciphertext = ciphertext[ns:]
  63. plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
  64. if err != nil {
  65. return nil, err
  66. }
  67. return plaintext, nil
  68. }