赞
踩
第四节:PBKDF2加密解密 - 前端crypto-js.min.js和后端UE4使用Crypto++互相加解密
有一个应用系统包含前端html和UE4后端。其中前端某一部分导航功能需要跳转至后端(简单的说就是前端现在要把后端中的所有功能包含进来),这里就涉及到前端登录后的权限要同步到后端,实现单点登录,针对外部用户就采用了PBKDF2加密的方式验证。实现思路: 在登录前端的情况下,外部用户点击跳转至后端的时候免登录,同步权限。这里是在跳转时,前后端协商采用PBKDF2的加解密对该用户进行校验。后端UE4使用Crypto++库,前端使用crypto-js.min.js进行PBKDF2的对应操作。经过测试,本例中的前后端代码的加密计算结果是能够互相验证成功的。
提示:以下是本篇文章正文内容,下面案例可供参考
前端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"> //--PBKDF2 function Pbkdf2Encrypt(pbkdf2_content, pbkdf2_key){ //PBKDF2加密 var srcs = CryptoJS.enc.Utf8.parse(pbkdf2_content); var key256Bits = CryptoJS.PBKDF2(srcs, pbkdf2_key, { keySize: 256 / 32, //Key的字节数:32 iterations: 1024, //迭代次数 // hasher: CryptoJS.algo.SHA256 //摘要算法-如果没有写这一行,默认是SHA1摘要算法 }); return key256Bits.toString().toUpperCase() //将Hex格式字符串转换为大写,以方便UE4对比 } function Pbkdf2Authenticate(attemptedPassword, encryptedPassword, pbkdf2_key){ //PBKDF2验证 var attemptedEncryptedPassword = Pbkdf2Encrypt(attemptedPassword, pbkdf2_key); return attemptedEncryptedPassword == encryptedPassword; } </script>
需要注意的是,前端crypto-js.min.js加密的Hex格式密文字符串是小写的,而后端大写的。所以前端发送密文前,需要将小写转换成大写。
后端UE4写二个函数,一个是加密函数,使用盐值加密字符串并将密文发送到后端进行验证。另一个是验证函数,需要接收前端发来的密文,对密文进行验证。
以下为实现逻辑:
PBKDF2LibraryBP.h
#pragma once #include "../ThirdParty/crypto/include/Win64/config_int.h" #include "../ThirdParty/crypto/include/Win64/pwdbased.h" #include "../ThirdParty/crypto/include/Win64/sha.h" #include "../ThirdParty/crypto/include/Win64/hex.h" #include "../ThirdParty/crypto/include/Win64/cryptlib.h" #include "../ThirdParty/crypto/include/Win64/blake2.h" #include "../ThirdParty/crypto/include/Win64/files.h" #include "../ThirdParty/crypto/include/Win64/aes.h" #include "../ThirdParty/crypto/include/Win64/modes.h" #include "../ThirdParty/crypto/include/Win64/pubkey.h" using namespace CryptoPP; #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "PBKDF2LibraryBP.generated.h" /** * */ UCLASS() class CRYPTO_API UPBKDF2LibraryBP : public UBlueprintFunctionLibrary { GENERATED_BODY() public: //PBKDF2算法 //验证密码 UFUNCTION(BlueprintCallable, meta = (DisplayName = "authenticate", Keywords = "authenticate", pbkdf2_key = "0123456789ABCDEF0123456789ABCDEF"), Category = "PBKDF2") static bool authenticate(FString attemptedPassword, FString encryptedPassword, FString pbkdf2_key); //生成密文 UFUNCTION(BlueprintCallable, meta = (DisplayName = "getEncryptedPassword", Keywords = "getEncryptedPassword", pbkdf2_key = "0123456789ABCDEF0123456789ABCDEF"), Category= "PBKDF2") static FString getEncryptedPassword(FString pbkdf2_content, FString pbkdf2_key); };
PBKDF2LibraryBP.cpp
#include "PBKDF2LibraryBP.h" /** * 对输入的password进行验证 * * @param attemptedPassword * 待验证的password * @param encryptedPassword * 密文 * @param salt * 盐值 * @return 是否验证成功 */ #pragma region PBKDF2 bool UPBKDF2LibraryBP::authenticate(FString attemptedPassword, FString encryptedPassword, FString salt) { // 用同样的盐值对用户输入的password进行加密 FString encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt); // 把加密后的密文和原密文进行比較,同样则验证成功。否则失败 return encryptedAttemptedPassword.Equals(encryptedPassword); } /** * 生成密文 * * @param password * 明文password * @param salt * 盐值 * @return */ FString UPBKDF2LibraryBP::getEncryptedPassword(FString pbkdf2_content, FString pbkdf2_key) { std::string _pbkdf2_content = TCHAR_TO_UTF8(*pbkdf2_content); byte password[AES::MAX_KEYLENGTH]; size_t plen = _pbkdf2_content.size(); plen <= AES::MAX_KEYLENGTH ? memcpy(password, _pbkdf2_content.c_str(), plen) : memcpy(password, _pbkdf2_content.c_str(), AES::MAX_KEYLENGTH); std::string _pbkdf2_key = TCHAR_TO_UTF8(*pbkdf2_key); byte salt[AES::MAX_KEYLENGTH]; size_t slen = _pbkdf2_key.size(); slen <= AES::MAX_KEYLENGTH ? memcpy(salt, _pbkdf2_key.c_str(), slen) : memcpy(salt, _pbkdf2_key.c_str(), AES::MAX_KEYLENGTH); byte derived[SHA256::DIGESTSIZE]; //密文长度要和前端一样 PKCS5_PBKDF2_HMAC<SHA1> pbkdf; //填充方式要和前端一样 byte unused = 0; pbkdf.DeriveKey(derived, sizeof(derived), unused, password, plen, salt, slen, 1024, 0.0f); std::string result; HexEncoder encoder(new StringSink(result)); encoder.Put(derived, sizeof(derived)); encoder.MessageEnd(); return UTF8_TO_TCHAR(result.c_str()); } #pragma endregion
将html页面加载到UE4中,运行效果如下:
后端UE4加密,前端html验证
前端html加密,后端UE4验证
完美实现前后端加密和验证。
一般情况下,前端自己实现加解密没有问题,后端自己实现加解密也没有问题。问题主要出在3个方面:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。