Note: This is only for personal use and learning, I am not trying to roll my own encryption for public use.
I need to AES256 encrypt a string, however my current attempts end up with a string like Salted__Vέ��|��l��ʼ8XCQlY
server side when it is hex decoded. It should rather be a valid utf8 base64 string when hex-decoded, which can then be decoded to the original string. This is similar to the solution offered here, however the salt was not the actual problem (despite the answer being accepted) and I have not been able to suppress the salt op by hex decoding the iv before use (as it suggested). Is there a way to do this?
I've tried several different methods and always end up in a similar spot. My latest attempt is such:
encrypt.js
// CryptoJS.pad.NoPadding={pad:function(){},unpad:function(){}};
const SECRET = '394812730425442A472D2F423F452848';
const iv = crypto.getRandomValues(new Uint8Array(16));
function enc(plainText) {
var b64 = CryptoJS.AES.encrypt(plainText, SECRET, {
iv,
mode: CryptoJS.mode.CBC,
// padding: CryptoJS.pad.NoPadding
}).toString();
// Don't need?
//var e64 = CryptoJS.enc.Base64.parse(b64);
//var eHex = e64.toString(CryptoJS.enc.Hex);
console.log("b64::", b64);
return b64;
}
enc("SUPA_SECRET");
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
Now we take the b64
result and paste it into the JS_GEN
variable in the server side golang decrypt:
decrypt.go
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"fmt"
)
func main() {
JS_GEN := "U2FsdGVkX1+CA3LZTXePlgoGqL8VkdgiDgUenZhH4kc="
SECRET := "394812730425442A472D2F423F452848"
//msg := "SUPER_SECRET"
res, err := DecryptCBC(SECRET, JS_GEN)
if err != nil {
fmt.Println(err)
}
fmt.Println("res::", res)
}
func DecryptCBC(secret string, target string) (string, error) {
nilString := ""
key, _ := hex.DecodeString(secret)
//ciphertext, err := base64.URLEncoding.DecodeString(target)
// Decode base64 string
ciphertext, err := base64.StdEncoding.DecodeString(target)
if err != nil {
return nilString, err
}
// Create new cipher block
block, err := aes.NewCipher(key)
if err != nil {
return nilString, err
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
// CBC mode always works in whole blocks.
if len(ciphertext)%aes.BlockSize != 0 {
panic("ciphertext is not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(ciphertext, ciphertext)
fmt.Println("ciphertext::", ciphertext)
// Output: exampleplaintext
return string(ciphertext), nil
}
The output will be something like:
ciphertext:: [136 227 244 124 124 92 162 254 1 147 235 213 8 136 129 150]
res:: ���||\�������
What am I doing wrong?
EDIT: I've removed hex encode/decode from the process.
</div>