I am trying to encrypt string on golang server, i have a aes-128 encrypt util
func EncryptAES(key []byte, plaintext string) (string, error) {
// create cipher
c, err := aes.NewCipher(key)
if err != nil {
return "", err
}
// allocate space for ciphered data
out := make([]byte, len(plaintext))
for i := 1; i <= len(plaintext)/16; i {
tempBuf := make([]byte, 16)
offset := (i - 1) * 16
limit := offset 16
// encrypt
c.Encrypt(tempBuf, []byte(plaintext[offset:limit]))
for j := 0; j < len(tempBuf); j {
out[offset j] = tempBuf[j]
}
}
// return hex string
return hex.EncodeToString(out), nil
}
and after that i am trying to do something like that
hasher := sha256.New()
hasher.Write([]byte(word))
sha := hasher.Sum(nil)
cypherText := word userSessionKey
for len([]byte(cypherText)) != 0 {
cypherText = "0"
}
sha128 := sha[:len(sha)/2]
captchaKey, err := utils.EncryptAES([]byte(hex.EncodeToString(sha128)), cypherText)
if err != nil {
SendErrorResponse(ctx, fasthttp.StatusInternalServerError, []byte("error generating aes session key " err.Error()))
return
}
but for this key and ciphertext i am getting this error on encryption/decryption aes site
js func for decoding not working too
async function decryptAES128(key, cipherText){
let hash = CryptoJS.SHA256(key).toString();
hash = hash.substring(0, hash.length/2);
console.log(hash);
console.log(cipherText)
const bytes = await CryptoJS.AES.decrypt(CryptoJS.enc.Hex.parse(cipherText), CryptoJS.enc.Hex.parse(hash), { mode: CryptoJS.mode.ECB });
return CryptoJS.enc.Utf8.stringify(bytes.words)
}
just prints nothing
CodePudding user response:
The Go code pads with 0x30 values if the size of the plaintext (cypherText
, a misleading term by the way) is not an integer multiple of the blocksize (16 bytes for AES). As key the UTF-8 encoding of the hex encoding of the first 16 bytes of the SHA256 value of the password (word
) is used. The ciphertext is hex encoded.
Decryption with the online tool fails because the online tool uses PKCS#7 padding and the ciphertext is Base64 decoded. For decryption to be possible, the default PKCS#7 padding must be disabled and the ciphertext must be hex decoded, see e.g. CyberChef.
Decryption with the JavaScript code fails because CryptoJS uses PKCS#7 padding by default, the key is hex decoded, and the ciphertext is not passed as CipherParams
object. For decryption to be possible, the default PKCS#7 padding must be disabled, the key must be UTF-8 encoded, and the ciphertext must be passed as a CipherParams
object:
var password = 'день';
var key = CryptoJS.SHA256(password).toString();
key = key.substring(0, key.length/2);
var ciphertext = '46ef70c1193fa29024595964a0eb0157c4e6602da6c1429f8a2b81146f79e798'
var decrypted = CryptoJS.AES.decrypt(
{ciphertext: CryptoJS.enc.Hex.parse(ciphertext)}, // Fix 1: pass a CipherParams object
CryptoJS.enc.Utf8.parse(key), // Fix2: UTF-8 encode the key
{ mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); // Fix 3: disable padding
console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
gives as decrypted, UTF-8 decoded data: деньBvFGlrXeWCnPTwFC00000000
.
Security: ECB does not use an IV and is therefore insecure. Nowadays, authenticated encryption is applied (e.g. GCM), but at least a mode with an IV (e.g. CBC).
Furthermore, it is insecure to use a digest as key derivation function (KDF). There are dedicated functions for this (e.g. Argon2 or PBKDF2). Also, the byte string of the KDF should be used directly and not the UTF-8 encoding of the hex encoding, which reduces security.
The 0x30 padding applied is generally unreliable. More reliable is e.g. PKCS#7 padding.