Encryption
This commit is contained in:
126
cryptojs/cryptojs.go
Normal file
126
cryptojs/cryptojs.go
Normal file
@ -0,0 +1,126 @@
|
||||
package cryptojs
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"crypto/md5"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"math/rand"
|
||||
"errors"
|
||||
|
||||
"git.meow.tf/tyler/go-pastee/evpkdf"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
const (
|
||||
keySize = 32
|
||||
)
|
||||
|
||||
func Encrypt(data, passphrase string) (string, error) {
|
||||
salt := make([]byte, 8)
|
||||
|
||||
if _, err := rand.Read(salt); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
key := make([]byte, keySize)
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
|
||||
keymat := evpkdf.New(md5.New, []byte(passphrase), salt, keySize + aes.BlockSize, 1)
|
||||
keymatbuf := bytes.NewReader(keymat)
|
||||
|
||||
n, err := keymatbuf.Read(key)
|
||||
|
||||
if n != keySize || err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
n, err = keymatbuf.Read(iv)
|
||||
|
||||
if n != aes.BlockSize || err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
padded, err := pkcs7Pad([]byte(data), block.BlockSize())
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ciphertext := make([]byte, len(padded))
|
||||
|
||||
cbc := cipher.NewCBCEncrypter(block, iv)
|
||||
cbc.CryptBlocks(ciphertext, padded)
|
||||
|
||||
return encode(ciphertext, salt), nil
|
||||
}
|
||||
|
||||
func Decrypt(b64, passphrase string) ([]byte, error) {
|
||||
salt, ct, err := decode(b64)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := make([]byte, keySize)
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
|
||||
keymat := evpkdf.New(md5.New, []byte(passphrase), salt, keySize + aes.BlockSize, 1)
|
||||
keymatbuf := bytes.NewReader(keymat)
|
||||
|
||||
n, err := keymatbuf.Read(key)
|
||||
|
||||
if n != keySize || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err = keymatbuf.Read(iv)
|
||||
|
||||
if n != aes.BlockSize || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cbc := cipher.NewCBCDecrypter(block, iv)
|
||||
cbc.CryptBlocks(ct, ct)
|
||||
|
||||
plain, err := pkcs7Unpad(ct, block.BlockSize())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return plain, nil
|
||||
}
|
||||
|
||||
func encode(ct []byte, salt []byte) string {
|
||||
b := []byte("Salted__")
|
||||
b = append(b, salt...)
|
||||
b = append(b, ct...)
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
func decode(b64 string) ([]byte, []byte, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(b64)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if string(decoded[0:8]) != "Salted__" {
|
||||
return nil, nil, errors.New("invalid data")
|
||||
}
|
||||
|
||||
return decoded[8:16], decoded[16:], nil
|
||||
}
|
47
cryptojs/cryptojs_test.go
Normal file
47
cryptojs/cryptojs_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package cryptojs
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_EncryptDecrypt(t *testing.T) {
|
||||
enc, err := Encrypt("testing123", "testing")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Unable to encrypt:", err)
|
||||
}
|
||||
|
||||
b, err := Decrypt(enc, "testing")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Unable to decrypt:", err)
|
||||
}
|
||||
|
||||
final := string(b)
|
||||
|
||||
if final != "testing123" {
|
||||
t.Fatal("Final text does not match:", final)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_WebsiteEncrypt(t *testing.T) {
|
||||
enc, err := Encrypt("Testing Paste.ee", "wXBbztgFOsZtTvhK1vcZlR7izK84bmUW")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Error:", err)
|
||||
}
|
||||
|
||||
if enc != "U2FsdGVkX183sL2jzqJiJdhIl0O7R9v46TIkKnORreGpUufYUsqjqYO9b++CSyvV" {
|
||||
t.Fatal("Unexpected output:", enc)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_WebsiteDecrypt(t *testing.T) {
|
||||
b, err := Decrypt("U2FsdGVkX183sL2jzqJiJdhIl0O7R9v46TIkKnORreGpUufYUsqjqYO9b++CSyvV", "wXBbztgFOsZtTvhK1vcZlR7izK84bmUW")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Unable to decrypt:", err)
|
||||
}
|
||||
|
||||
if string(b) != "Testing Paste.ee" {
|
||||
t.Fatal("Unexpected output:", string(b))
|
||||
}
|
||||
}
|
48
cryptojs/pkcs7.go
Normal file
48
cryptojs/pkcs7.go
Normal file
@ -0,0 +1,48 @@
|
||||
package cryptojs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// Appends padding.
|
||||
func pkcs7Pad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen <= 0 {
|
||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||
}
|
||||
padlen := uint8(1)
|
||||
for ((len(data) + int(padlen)) % blocklen) != 0 {
|
||||
padlen++
|
||||
}
|
||||
|
||||
if int(padlen) > blocklen {
|
||||
panic(fmt.Sprintf("generated invalid padding length %v for block length %v", padlen, blocklen))
|
||||
}
|
||||
pad := bytes.Repeat([]byte{byte(padlen)}, int(padlen))
|
||||
return append(data, pad...), nil
|
||||
}
|
||||
|
||||
// Returns slice of the original data without padding.
|
||||
func pkcs7Unpad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen <= 0 {
|
||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||
}
|
||||
if len(data)%blocklen != 0 || len(data) == 0 {
|
||||
return nil, fmt.Errorf("invalid data len %d", len(data))
|
||||
}
|
||||
|
||||
padlen := int(data[len(data)-1])
|
||||
if padlen > blocklen || padlen == 0 {
|
||||
// Not padded
|
||||
return data, nil
|
||||
}
|
||||
// check padding
|
||||
pad := data[len(data)-padlen:]
|
||||
for i := 0; i < padlen; i++ {
|
||||
if pad[i] != byte(padlen) {
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
|
||||
return data[:len(data)-padlen], nil
|
||||
}
|
Reference in New Issue
Block a user