AES加密解密 - 前端crypto-js.min.js和后端UE4使用Crypto++互相加解密

UE4中Crypto++库加密解密

第二节:AES加密解密 - 前端crypto-js.min.js和后端UE4使用Crypto++互相加解密



前言

有一个应用系统包含前端html和UE4后端。其中前端某一部分导航功能需要跳转至后端(简单的说就是前端现在要把后端中的所有功能包含进来),这里就涉及到前端登录后的权限要同步到后端,实现单点登录,针对外部用户就采用了aes加密的方式验证。 实现思路: 在登录前端的情况下,外部用户点击跳转至后端的时候免登录,同步权限。这里是在跳转时,前后端协商采用aes的加解密对该用户进行校验。后端UE4使用Crypto++库,前端使用crypto-js.min.js进行AES的对应操作。经过测试,本例中的前后端代码的加密解密计算结果是一致的。


提示:以下是本篇文章正文内容,下面案例可供参考

一、前端

前端html写两个函数,一个是加密函数,使用公钥加密字符串并将密文发送到后端进行解密。另一个是解密函数,需要接收后端发来的密文,并使用私钥将密文解密成明文。

<script src="./crypto-js.min.js"></script>
<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>

<script type = "text/javascript">
//--AES
    function AesEncrypt(type, content, aesKey){ //AES加密

        var cipherStr = "";
        var srcs = CryptoJS.enc.Utf8.parse(content);
        switch(type)
        {
            case "AES":
                cipherStr = CryptoJS.AES.encrypt(srcs, aesKey, {
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.ZeroPadding
            }).toString();
        }        

        var words = CryptoJS.enc.Base64.parse(cipherStr);   //将Base64编码转换为WordArray对象
        var hex = CryptoJS.enc.Hex.stringify(words);        //WordArray对象转换为hex编码
        return hex;
    }

    function AesDecrypt(hexStr, aesKey){    //AES解密
        var words = CryptoJS.enc.Hex.parse(hexStr);             //将hex编码解析转换为WordArray对象
        var ciphertext = CryptoJS.enc.Base64.stringify(words);  //WordArray对象转换为base64编码
        var bytes  = CryptoJS.AES.decrypt(ciphertext, aesKey, {
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.ZeroPadding
            });
        var originalText = bytes.toString(CryptoJS.enc.Utf8);
        return originalText;
    }    

</script>

需要注意的是,前端crypto-js.min.js加密的密文是base64格式的,而后端Crypto++是hex格式的。所以前端发送密文前,需要将密文转换为hex格式。前端接收密文后,需要将密文转换为base64格式。

二、后端

后端UE4写二个函数,一个是生成公私密钥函数。一个是加密函数,使用公钥加密字符串并将密文发送到前端进行解密。另一个是解密函数,需要接收前端发来的密文,并使用私钥将密文解密成明文。
以下为实现逻辑:

1. C++代码

MyBlueprintFunctionLibrary.h

#pragma once

#include "CoreMinimal.h"

#include <ThirdParty/CryptoPP/5.6.5/include/config_int.h>
#include <ThirdParty/CryptoPP/5.6.5/include/osrng.h>

#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyBlueprintFunctionLibrary.generated.h"

/**
 * 
 */
UCLASS()
class TEST_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
public:	

	///ECB mode
	//AES加密
	UFUNCTION(BlueprintCallable, meta = (DisplayName = "ECB_AESEncryptData_H", Keywords = "ECB_AESEncryptData", aes_key = "0123456789ABCDEF0123456789ABCDEF"), Category = "AES")
		static FString ECB_AESEncryptData(FString aes_content, FString aes_key);

	//AES解密
	UFUNCTION(BlueprintCallable, meta = (DisplayName = "ECB_AESDecryptData_H", Keywords = "ECB_AESDecryptData", aes_key = "0123456789ABCDEF0123456789ABCDEF"), Category = "AES")
		static FString ECB_AESDecryptData(FString aes_content, FString aes_key, bool & result);
		
}

MyBlueprintFunctionLibrary.cpp

#include "MyBlueprintFunctionLibrary.h"

#include <base64.h>

#include "assert.h"
#include "randpool.h"

#include "string.h"
using namespace std;

#include "../../ThirdParty/crypto/include/Win64/aes.h"
#include "../../ThirdParty/crypto/include/Win64/hex.h"
#include "../../ThirdParty/crypto/include/Win64/modes.h"
#include "../../ThirdParty/crypto/include/Win64/rijndael.h"
#include "../../ThirdParty/crypto/include/Win64/pwdbased.h"
using namespace CryptoPP;

#include "../../ThirdParty/crypto/include/Win64/rsa.h"
using CryptoPP::RSA;
using CryptoPP::InvertibleRSAFunction;
using CryptoPP::RSAES_OAEP_SHA_Encryptor;
using CryptoPP::RSAES_OAEP_SHA_Decryptor;

#include "../../ThirdParty/crypto/include/Win64/sha.h"
using CryptoPP::SHA1;

#include "../../ThirdParty/crypto/include/Win64/files.h"
using CryptoPP::FileSink;
using CryptoPP::FileSource;

#include "../../ThirdParty/crypto/include/Win64/osrng.h"
using CryptoPP::AutoSeededRandomPool;

#include "../../ThirdParty/crypto/include/Win64/SecBlock.h"
using CryptoPP::SecByteBlock;

#include "../../ThirdParty/crypto/include/Win64/cryptlib.h"
using CryptoPP::Exception;
using CryptoPP::DecodingResult;


#pragma region ECB

FString UMyBlueprintFunctionLibrary::ECB_AESEncryptData(FString aes_content, FString aes_key)
{
	std::string sKey = TCHAR_TO_UTF8(*aes_key);
	const char *plainText = TCHAR_TO_ANSI(*aes_content);
	std::string outstr;

	//填key    
	SecByteBlock key(AES::MAX_KEYLENGTH);
	memset(key, 0x30, key.size());
	sKey.size() <= AES::MAX_KEYLENGTH ? memcpy(key, sKey.c_str(), sKey.size()) : memcpy(key, sKey.c_str(), AES::MAX_KEYLENGTH);
	
	AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
	
	ECB_Mode_ExternalCipher::Encryption ecbEncryption(aesEncryption);
	StreamTransformationFilter ecbEncryptor(
		ecbEncryption,
		new HexEncoder(new StringSink(outstr)),
		BlockPaddingSchemeDef::BlockPaddingScheme::ZEROS_PADDING
	);
	ecbEncryptor.Put((byte *)plainText, strlen(plainText));
	ecbEncryptor.MessageEnd();
	return UTF8_TO_TCHAR(outstr.c_str());	
}

FString UMyBlueprintFunctionLibrary::ECB_AESDecryptData(FString aes_content, FString aes_key, bool & result)
{
	std::string sKey = TCHAR_TO_UTF8(*aes_key);
	const char *cipherText = TCHAR_TO_ANSI(*aes_content);
	std::string outstr;
	try
	{
		//填key    
		SecByteBlock key(AES::MAX_KEYLENGTH);
		memset(key, 0x30, key.size());
		sKey.size() <= AES::MAX_KEYLENGTH ? memcpy(key, sKey.c_str(), sKey.size()) : memcpy(key, sKey.c_str(), AES::MAX_KEYLENGTH);
		
		ECB_Mode<AES >::Decryption ecbDecryption((byte *)key, AES::MAX_KEYLENGTH);
		
		HexDecoder decryptor(
			new StreamTransformationFilter(
				ecbDecryption,
				new StringSink(outstr),
				BlockPaddingSchemeDef::BlockPaddingScheme::ZEROS_PADDING
		));
		decryptor.Put((byte *)cipherText, strlen(cipherText));
		decryptor.MessageEnd();
		result = true;
	}
	catch (const std::exception& e)
	{
		outstr = "error";
		outstr = e.what();
		UE_LOG(LogTemp, Error, TEXT("ECB_AESDecryptData failed!"));
		result = false;
	}
	return UTF8_TO_TCHAR(outstr.c_str());
}

2. 蓝图

在这里插入图片描述

测试结果

将html页面加载到UE4中,运行效果如下:

  1. 后端UE4加密,前端html解密
    在这里插入图片描述

  2. 前端html加密,后端UE4解密
    在这里插入图片描述

完美实现前后端加解密。


总结

一般情况下,前端自己实现加解密没有问题,后端自己实现加解密也没有问题。问题主要出在3个方面:

  1. 前后端编码格式不一样
    前端加密的结果传到后端,或者后端加密的结果传到前端,对方无法识别接收到的字符串。主要原因在于双方的字符串编码格式不一样,前端的是base64格式,后端的是hex格式,这样就需要将格式进行转换。
  2. 填充方式不一样
    在这里,前端加密库使用ZeroPadding标准填充,所以后端也要使用ZEROS_PADDING方式填充。
  3. 分组密码操作模式不一样
    在这里,前端加密库使用ECB分组密码操作模式,所以后端也要使用ECB分组密码操作模式。

参考

使用crypto-js进行128位AES/ECB/PKCS7Padding加密/解密
使用 Crypto.js AES加密 CDN引用方式
crypto-js文档
crypto-js文档2
crypto-js文档3
crypto-廖雪峰的官方网站
在线RSA公钥加密解密

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值