123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- package rncryptor
- import(
- "bytes"
- "errors"
- "crypto/rand"
- "crypto/sha1"
- "crypto/sha256"
- "crypto/hmac"
- "crypto/aes"
- "crypto/cipher"
- "golang.org/x/crypto/pbkdf2"
- )
- func Decrypt(password string, data []byte) ([]byte, error) {
- version := data[:1]
- options := data[1:2]
- encSalt := data[2:10]
- hmacSalt := data[10:18]
- iv := data[18:34]
- cipherText := data[34:(len(data)-66+34)]
- expectedHmac := data[len(data)-32:len(data)]
- msg := make([]byte, 0)
- msg = append(msg, version...)
- msg = append(msg, options...)
- msg = append(msg, encSalt...)
- msg = append(msg, hmacSalt...)
- msg = append(msg, iv...)
- msg = append(msg, cipherText...)
- hmacKey := pbkdf2.Key([]byte(password), hmacSalt, 10000, 32, sha1.New)
- testHmac := hmac.New(sha256.New, hmacKey)
- testHmac.Write(msg)
- testHmacVal := testHmac.Sum(nil)
- // its important to use hmac.Equal to not leak time
- // information. See https://github.com/RNCryptor/RNCryptor-Spec
- verified := hmac.Equal(testHmacVal, expectedHmac)
- if !verified {
- return nil, errors.New("Password may be incorrect, or the data has been corrupted. (HMAC could not be verified)")
- }
- cipherKey := pbkdf2.Key([]byte(password), encSalt, 10000, 32, sha1.New)
- cipherBlock, err := aes.NewCipher(cipherKey)
- if err != nil {
- return nil, err
- }
- decrypted := make([]byte, len(cipherText))
- copy(decrypted, cipherText)
- decrypter := cipher.NewCBCDecrypter(cipherBlock, iv)
- decrypter.CryptBlocks(decrypted, decrypted)
- // un-padd decrypted data
- length := len(decrypted)
- unpadding := int(decrypted[length-1])
- return decrypted[:(length - unpadding)], nil
- }
- func Encrypt(password string, data []byte) ([]byte, error) {
- encSalt, encSaltErr := RandBytes(8)
- if encSaltErr != nil {
- return nil, encSaltErr
- }
- hmacSalt, hmacSaltErr := RandBytes(8)
- if hmacSaltErr != nil {
- return nil, hmacSaltErr
- }
- iv, ivErr := RandBytes(16)
- if ivErr != nil {
- return nil, ivErr
- }
- encrypted, encErr := EncryptWithOptions(password, data, encSalt, hmacSalt, iv)
- if encErr != nil {
- return nil, encErr
- }
- return encrypted, nil
- }
- func EncryptWithOptions(password string, data, encSalt, hmacSalt, iv []byte) ([]byte, error) {
- if len(password) < 1 {
- return nil, errors.New("Password cannot be empty")
- }
- encKey := pbkdf2.Key([]byte(password), encSalt, 10000, 32, sha1.New)
- hmacKey := pbkdf2.Key([]byte(password), hmacSalt, 10000, 32, sha1.New)
- cipherText := make([]byte, len(data))
- copy(cipherText, data)
- version := byte(3)
- options := byte(1)
- msg := make([]byte, 0)
- msg = append(msg, version)
- msg = append(msg, options)
- msg = append(msg, encSalt...)
- msg = append(msg, hmacSalt...)
- msg = append(msg, iv...)
- cipherBlock, cipherBlockErr := aes.NewCipher(encKey)
- if cipherBlockErr != nil {
- return nil, cipherBlockErr
- }
- // padd text for encryption
- blockSize := cipherBlock.BlockSize()
- padding := blockSize - len(cipherText)%blockSize
- padText := bytes.Repeat([]byte{byte(padding)}, padding)
- cipherText = append(cipherText, padText...)
- encrypter := cipher.NewCBCEncrypter(cipherBlock, iv)
- encrypter.CryptBlocks(cipherText, cipherText)
- msg = append(msg, cipherText...)
- hmacSrc := hmac.New(sha256.New, hmacKey)
- hmacSrc.Write(msg)
- hmacVal := hmacSrc.Sum(nil)
- msg = append(msg, hmacVal...)
- return msg, nil
- }
- func RandBytes(num int64) ([]byte, error) {
- bits := make([]byte, num)
- _, err := rand.Read(bits)
- if err != nil {
- return nil, err
- }
- return bits, nil
- }
|