rncryptor.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package rncryptor
  2. import(
  3. "bytes"
  4. "errors"
  5. "crypto/rand"
  6. "crypto/sha1"
  7. "crypto/sha256"
  8. "crypto/hmac"
  9. "crypto/aes"
  10. "crypto/cipher"
  11. "golang.org/x/crypto/pbkdf2"
  12. )
  13. func Decrypt(password string, data []byte) ([]byte, error) {
  14. version := data[:1]
  15. options := data[1:2]
  16. encSalt := data[2:10]
  17. hmacSalt := data[10:18]
  18. iv := data[18:34]
  19. cipherText := data[34:(len(data)-66+34)]
  20. expectedHmac := data[len(data)-32:len(data)]
  21. msg := make([]byte, 0)
  22. msg = append(msg, version...)
  23. msg = append(msg, options...)
  24. msg = append(msg, encSalt...)
  25. msg = append(msg, hmacSalt...)
  26. msg = append(msg, iv...)
  27. msg = append(msg, cipherText...)
  28. hmacKey := pbkdf2.Key([]byte(password), hmacSalt, 10000, 32, sha1.New)
  29. testHmac := hmac.New(sha256.New, hmacKey)
  30. testHmac.Write(msg)
  31. testHmacVal := testHmac.Sum(nil)
  32. // its important to use hmac.Equal to not leak time
  33. // information. See https://github.com/RNCryptor/RNCryptor-Spec
  34. verified := hmac.Equal(testHmacVal, expectedHmac)
  35. if !verified {
  36. return nil, errors.New("Password may be incorrect, or the data has been corrupted. (HMAC could not be verified)")
  37. }
  38. cipherKey := pbkdf2.Key([]byte(password), encSalt, 10000, 32, sha1.New)
  39. cipherBlock, err := aes.NewCipher(cipherKey)
  40. if err != nil {
  41. return nil, err
  42. }
  43. decrypted := make([]byte, len(cipherText))
  44. copy(decrypted, cipherText)
  45. decrypter := cipher.NewCBCDecrypter(cipherBlock, iv)
  46. decrypter.CryptBlocks(decrypted, decrypted)
  47. // un-padd decrypted data
  48. length := len(decrypted)
  49. unpadding := int(decrypted[length-1])
  50. return decrypted[:(length - unpadding)], nil
  51. }
  52. func Encrypt(password string, data []byte) ([]byte, error) {
  53. encSalt, encSaltErr := RandBytes(8)
  54. if encSaltErr != nil {
  55. return nil, encSaltErr
  56. }
  57. hmacSalt, hmacSaltErr := RandBytes(8)
  58. if hmacSaltErr != nil {
  59. return nil, hmacSaltErr
  60. }
  61. iv, ivErr := RandBytes(16)
  62. if ivErr != nil {
  63. return nil, ivErr
  64. }
  65. encrypted, encErr := EncryptWithOptions(password, data, encSalt, hmacSalt, iv)
  66. if encErr != nil {
  67. return nil, encErr
  68. }
  69. return encrypted, nil
  70. }
  71. func EncryptWithOptions(password string, data, encSalt, hmacSalt, iv []byte) ([]byte, error) {
  72. if len(password) < 1 {
  73. return nil, errors.New("Password cannot be empty")
  74. }
  75. encKey := pbkdf2.Key([]byte(password), encSalt, 10000, 32, sha1.New)
  76. hmacKey := pbkdf2.Key([]byte(password), hmacSalt, 10000, 32, sha1.New)
  77. cipherText := make([]byte, len(data))
  78. copy(cipherText, data)
  79. version := byte(3)
  80. options := byte(1)
  81. msg := make([]byte, 0)
  82. msg = append(msg, version)
  83. msg = append(msg, options)
  84. msg = append(msg, encSalt...)
  85. msg = append(msg, hmacSalt...)
  86. msg = append(msg, iv...)
  87. cipherBlock, cipherBlockErr := aes.NewCipher(encKey)
  88. if cipherBlockErr != nil {
  89. return nil, cipherBlockErr
  90. }
  91. // padd text for encryption
  92. blockSize := cipherBlock.BlockSize()
  93. padding := blockSize - len(cipherText)%blockSize
  94. padText := bytes.Repeat([]byte{byte(padding)}, padding)
  95. cipherText = append(cipherText, padText...)
  96. encrypter := cipher.NewCBCEncrypter(cipherBlock, iv)
  97. encrypter.CryptBlocks(cipherText, cipherText)
  98. msg = append(msg, cipherText...)
  99. hmacSrc := hmac.New(sha256.New, hmacKey)
  100. hmacSrc.Write(msg)
  101. hmacVal := hmacSrc.Sum(nil)
  102. msg = append(msg, hmacVal...)
  103. return msg, nil
  104. }
  105. func RandBytes(num int64) ([]byte, error) {
  106. bits := make([]byte, num)
  107. _, err := rand.Read(bits)
  108. if err != nil {
  109. return nil, err
  110. }
  111. return bits, nil
  112. }