PHP中有個函式:hash_hmac(‘sha512’, $data, $key)
請大神移植到VBA中。(如果有VB現成的也可以)
我想自己移值,但有以下不理解:
其實,我對這個函式理解有些疑問:按我的理解,哈希(Sha512)是對$data求散列值,怎么這里多出一個$key呢?$key按解釋來說,就是作為密碼,進行驗證,難不成Sha512計算可逆?
(我的理解:Sha512本質是一元計算,就是只需要一個引數,且計算不可逆)
uj5u.com熱心網友回復:
求“散列值”的演算法,應該都是不可逆的吧。你既然接觸到PHP,那你首先應該搞清楚hash_hmac()的作用、各個引數的含義吧!
按一般的API規律,實作sha512演算法的函式,一個是輸入資料的指標(資料首址),另一個會是資料長度(資料有多少位元組)。
你這兒的 $Key 會不會并不是密碼,而是表示資料長度的變數呢?
uj5u.com熱心網友回復:
使用 key 的目的,是使用驗證者能夠確認 MAC 來自 key 的持有者。首先,你找到一段求 SHA-512 的代碼,作為處理的核心。
其次,按以下流程處理:
1. 將 key 用后續 0 填充成一個訊息分組(128 位元組)。我們暫且稱其為密鑰塊。
2. 將密鑰塊所有位元組與 &H36(ipad)異或得到輸入首分組。
3. 將訊息(data)填充后鏈接在輸入首分組之后,用 SHA-512 求 Hash。
4. 將密鑰塊所有位元組與 &H5C(opad)異或得到輸出首分組。
5. 將 Hash 作為訊息填充后鏈接在輸出首分組之后,用 SHA-512 求 MAC。
6. 截取你所需要的長度。
uj5u.com熱心網友回復:
不要做A語言代碼修改為B語言代碼的無用功。也不要做用A語言代碼直接呼叫B語言代碼庫這樣復雜、這樣容易出錯的傻事。
只需讓A、B語言代碼的輸入輸出重定向到文本檔案,或修改A、B語言代碼讓其通過文本檔案輸入輸出。
即可很方便地讓A、B兩種語言之間協調作業。
比如:
A將請求資料寫到檔案a.txt,寫完后改名為aa.txt
B發現aa.txt存在時,讀取其內容,呼叫相應功能,將結果寫到檔案b.txt,寫完后洗掉aa.txt,改名為bb.txt
A發現bb.txt存在時,讀取其內容,讀完后洗掉bb.txt
以上A可以替換為任何一種開發語言或開發環境,B可以替換為任何一種與A不同的開發語言或開發環境。
除非A或B不支持判斷檔案是否存在、檔案讀寫和檔案更名。
但是誰又能舉出不支持判斷檔案是否存在、檔案讀寫和檔案更名的開發語言或開發環境呢?
可以將臨時檔案放在RamDisk上提高效率減少磨損磁盤。
資料的結構很復雜的話,文本檔案的格式問題可參考json或xml
共享臨時文本檔案這種行程之間的通訊方法相比其它方法的優點有很多,下面僅列出我現在能想到的:
·行程之間松耦合
·行程可在同一臺機器上,也可跨機,跨作業系統,跨硬體平臺,甚至跨國。
·方便除錯和監視,只需讓第三方或人工查看該臨時文本檔案即可。
·方便在線開關服務,只需洗掉或創建該臨時文本檔案即可。
·方便實作分布式和負載均衡。
·方便佇列化提供服務,而且幾乎不可能發生佇列滿的情況(除非硬碟空間滿)
·……
“跨語言、跨機,跨作業系統,跨硬體平臺,跨國,跨*.*的”苦海無邊,
回頭是“使用共享純文本檔案進行資訊交流”的岸!
uj5u.com熱心網友回復:
NONONO!怪我沒說清楚,我說是要移值,其實不是真的移值,我本來就是用VBA來寫程式的,只是。。。。我要編的東西,網站上只給出了一個PHP范例,我不能因為人家給的PHP范例,就搭個臺子去學PHP,您說是吧?
話說PHP編就是方便,(但搭建編程分環境就不是那么友好了,各有優缺點吧),PHP中一個函式就能搞定的東西,VB要搞半天,還不明白。在此解釋一下PHP這個函式的用法:(我在網上查的)
hash_hmac — 使用 HMAC 方法生成帶有密鑰的哈希值
string hash_hmac(string $algo, string $data, string $key[, bool $raw_output = false])
引數:
algo:要使用的哈希演算法名稱,例如:"md5","sha256","haval160,4", "sha512""等。
data:要進行哈希運算的訊息。
key:使用 HMAC 生成資訊摘要時所使用的密鑰。
raw_output:(此引數為可選)設定為 TRUE 輸出原始二進制資料, 設定為 FALSE 輸出小寫 16 進制字串。
回傳值:
如果 raw_output 設定為 TRUE, 則回傳原始二進制資料表示的資訊摘要,否則回傳 16 進制小寫字串格式表示的資訊摘要。
如果 algo 引數指定的不是受支持的演算法,回傳 FALSE。
此函式一般情形回傳一個對應哈希位數的16進制資訊摘要(sha512回傳128位的16進制形式的字串)
問:VBA中怎么解決?
uj5u.com熱心網友回復:
首先,感謝您的回答!
在此解釋一下PHP這個函式的用法:四個引數,我的例子用了三個,前三個引數必選,第四個為可選引數(我在網上查的)
hash_hmac — 使用 HMAC 方法生成帶有密鑰的哈希值 (帶有密鑰的哈希值,這怎么理解)
string hash_hmac(string $algo, string $data, string $key[, bool $raw_output = false])
引數:
algo:要使用的哈希演算法名稱,例如:"md5","sha256","haval160,4", "sha512""等。
data:要進行哈希運算的訊息。
key:使用 HMAC 生成資訊摘要時所使用的密鑰。
raw_output:(此引數為可選)設定為 TRUE 輸出原始二進制資料, 設定為 FALSE 輸出小寫 16 進制字串。
回傳值:
如果 raw_output 設定為 TRUE, 則回傳原始二進制資料表示的資訊摘要,否則回傳 16 進制小寫字串格式表示的資訊摘要。
如果 algo 引數指定的不是受支持的演算法,回傳 FALSE。
此函式一般情形回傳一個對應哈希位數的16進制資訊摘要(sha512回傳128位的16進制形式的字串)
問:VBA中怎么解決?
uj5u.com熱心網友回復:
對了,類似Sha512($data)
的函式已經有了。就問下,怎么弄出:帶有密鑰的哈希值?
uj5u.com熱心網友回復:
僅供參考:#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#define _WIN32_WINNT 0x0400
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#define KEYLENGTH 0x00800000
void HandleError(char *s);
//--------------------------------------------------------------------
// These additional #define statements are required.
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
// Declare the function EncryptFile. The function definition
// follows main.
BOOL EncryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword);
//--------------------------------------------------------------------
// Begin main.
void main(void) {
CHAR szSource[100];
CHAR szDestination[100];
CHAR szPassword[100];
printf("Encrypt a file. \n\n");
printf("Enter the name of the file to be encrypted: ");
scanf("%s",szSource);
printf("Enter the name of the output file: ");
scanf("%s",szDestination);
printf("Enter the password:");
scanf("%s",szPassword);
//--------------------------------------------------------------------
// Call EncryptFile to do the actual encryption.
if(EncryptFile(szSource, szDestination, szPassword)) {
printf("Encryption of the file %s was a success. \n", szSource);
printf("The encrypted data is in file %s.\n",szDestination);
} else {
HandleError("Error encrypting file!");
}
} // End of main
//--------------------------------------------------------------------
// Code for the function EncryptFile called by main.
static BOOL EncryptFile(
PCHAR szSource,
PCHAR szDestination,
PCHAR szPassword)
//--------------------------------------------------------------------
// Parameters passed are:
// szSource, the name of the input, a plaintext file.
// szDestination, the name of the output, an encrypted file to be
// created.
// szPassword, the password.
{
//--------------------------------------------------------------------
// Declare and initialize local variables.
FILE *hSource;
FILE *hDestination;
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
PBYTE pbBuffer;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
//--------------------------------------------------------------------
// Open source file.
if(hSource = fopen(szSource,"rb")) {
printf("The source plaintext file, %s, is open. \n", szSource);
} else {
HandleError("Error opening source plaintext file!");
}
//--------------------------------------------------------------------
// Open destination file.
if(hDestination = fopen(szDestination,"wb")) {
printf("Destination file %s is open. \n", szDestination);
} else {
HandleError("Error opening destination ciphertext file!");
}
//以下獲得一個CSP句柄
if(CryptAcquireContext(
&hCryptProv,
NULL, //NULL表示使用默認密鑰容器,默認密鑰容器名
//為用戶登陸名
NULL,
PROV_RSA_FULL,
0)) {
printf("A cryptographic provider has been acquired. \n");
} else {
if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))//創建密鑰容器
{
//創建密鑰容器成功,并得到CSP句柄
printf("A new key container has been created.\n");
} else {
HandleError("Could not create a new key container.\n");
}
}
//--------------------------------------------------------------------
// 創建一個會話密鑰(session key)
// 會話密鑰也叫對稱密鑰,用于對稱加密演算法。
// (注: 一個Session是指從呼叫函式CryptAcquireContext到呼叫函式
// CryptReleaseContext 期間的階段。會話密鑰只能存在于一個會話程序)
//--------------------------------------------------------------------
// Create a hash object.
if(CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash)) {
printf("A hash object has been created. \n");
} else {
HandleError("Error during CryptCreateHash!\n");
}
//--------------------------------------------------------------------
// 用輸入的密碼產生一個散列
if(CryptHashData(
hHash,
(BYTE *)szPassword,
strlen(szPassword),
0)) {
printf("The password has been added to the hash. \n");
} else {
HandleError("Error during CryptHashData. \n");
}
//--------------------------------------------------------------------
// 通過散列生成會話密鑰
if(CryptDeriveKey(
hCryptProv,
ENCRYPT_ALGORITHM,
hHash,
KEYLENGTH,
&hKey)) {
printf("An encryption key is derived from the password hash. \n");
} else {
HandleError("Error during CryptDeriveKey!\n");
}
//--------------------------------------------------------------------
// Destroy the hash object.
CryptDestroyHash(hHash);
hHash = NULL;
//--------------------------------------------------------------------
// The session key is now ready.
//--------------------------------------------------------------------
// 因為加密演算法是按ENCRYPT_BLOCK_SIZE 大小的塊加密的,所以被加密的
// 資料長度必須是ENCRYPT_BLOCK_SIZE 的整數倍。下面計算一次加密的
// 資料長度。
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
//--------------------------------------------------------------------
// Determine the block size. If a block cipher is used,
// it must have room for an extra block.
if(ENCRYPT_BLOCK_SIZE > 1)
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
dwBufferLen = dwBlockLen;
//--------------------------------------------------------------------
// Allocate memory.
if(pbBuffer = (BYTE *)malloc(dwBufferLen)) {
printf("Memory has been allocated for the buffer. \n");
} else {
HandleError("Out of memory. \n");
}
//--------------------------------------------------------------------
// In a do loop, encrypt the source file and write to the destination file.
do {
//--------------------------------------------------------------------
// Read up to dwBlockLen bytes from the source file.
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
if(ferror(hSource)) {
HandleError("Error reading plaintext!\n");
}
//--------------------------------------------------------------------
// 加密資料
if(!CryptEncrypt(
hKey, //密鑰
0, //如果資料同時進行散列和加密,這里傳入一個
//散列物件
feof(hSource), //如果是最后一個被加密的塊,輸入TRUE.如果不是輸.
//入FALSE這里通過判斷是否到檔案尾來決定是否為
//最后一塊。
0, //保留
pbBuffer, //輸入被加密資料,輸出加密后的資料
&dwCount, //輸入被加密資料實際長度,輸出加密后資料長度
dwBufferLen)) //pbBuffer的大小。
{
HandleError("Error during CryptEncrypt. \n");
}
//--------------------------------------------------------------------
// Write data to the destination file.
fwrite(pbBuffer, 1, dwCount, hDestination);
if(ferror(hDestination)) {
HandleError("Error writing ciphertext.");
}
} while(!feof(hSource));
//--------------------------------------------------------------------
// End the do loop when the last block of the source file has been
// read, encrypted, and written to the destination file.
//--------------------------------------------------------------------
// Close files.
if(hSource)
fclose(hSource);
if(hDestination)
fclose(hDestination);
//--------------------------------------------------------------------
// Free memory.
if(pbBuffer)
free(pbBuffer);
//--------------------------------------------------------------------
// Destroy session key.
if(hKey)
CryptDestroyKey(hKey);
//--------------------------------------------------------------------
// Destroy hash object.
if(hHash)
CryptDestroyHash(hHash);
//--------------------------------------------------------------------
// Release provider handle.
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
return(TRUE);
} // End of Encryptfile
//--------------------------------------------------------------------
// This example uses the function HandleError, a simple error
// handling function, to print an error message to the standard error
// (stderr) file and exit the program.
// For most applications, replace this function with one
// that does more extensive error reporting.
void HandleError(char *s) {
fprintf(stderr,"An error occurred in running the program. \n");
fprintf(stderr,"%s\n",s);
fprintf(stderr, "Error number %x.\n", GetLastError());
fprintf(stderr, "Program terminating. \n");
exit(1);
} // End of HandleError
uj5u.com熱心網友回復:
再供參考:#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
void HandleError(TCHAR* s);
void Wait(TCHAR* s);
int _tmain(int argc, _TCHAR* argv[]) {
HCRYPTPROV hProv;
LPTSTR pszName;
DWORD dwType;
DWORD cbName;
DWORD dwIndex = 0;
BYTE* ptr;
ALG_ID aiAlgid;
DWORD dwBits;
DWORD dwNameLen;
CHAR szName[100];
BYTE pbData[1024];
DWORD cbData = 1024;
DWORD dwIncrement = sizeof(DWORD);
DWORD dwFlags = CRYPT_FIRST;
DWORD dwParam = PP_CLIENT_HWND;
CHAR* pszAlgType = NULL;
BOOL fMore = TRUE;
printf("列舉可用的CSP提供者型別\n");
printf("CSP提供者型別 CSP提供者型別名稱\n");
_tprintf(TEXT("_____________ __________________________________________________\n"));
//回圈呼叫CryptEnumProviderType函式列舉當前計算機支持的CSP型別
while(CryptEnumProviderTypes(dwIndex, NULL, 0,
&dwType,
NULL, //第一次呼叫設定為NULL
&cbName)) //將要輸出的pszName的長度
{
//為pszName分配記憶體
if(!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName))) {
HandleError(TEXT("呼叫LocalAlloc分配記憶體出錯\n"));
}
//獲取CSP提供者型別名
if(CryptEnumProviderTypes(dwIndex++, NULL, 0,
&dwType, pszName, &cbName)) {
_tprintf(TEXT("%13d %s\n"), dwType, pszName);
} else {
HandleError(TEXT("呼叫CryptEnumProviderTypes出錯\n"));
}
LocalFree(pszName);
}
//連接CSP,創建CSP句柄
if(!CryptAcquireContext(&hProv, NULL, NULL,
PROV_RSA_FULL, NULL)) {
HandleError(TEXT("呼叫CryptAcquireContext函式出錯\n"));
}
//獲得CSP引數,列舉支持的密碼演算法
printf("\n列舉支持的密碼演算法\n");
printf("演算法ID 位數 型別 長度 演算法名稱\n");
printf("_________ ____ ____ ____ ____________________\n");
while(fMore) {
if(CryptGetProvParam(hProv, PP_ENUMALGS, pbData,
&cbData, dwFlags)) {
//從pbData緩沖區中決議出演算法資訊
dwFlags = 0;
ptr = pbData;
aiAlgid = *(ALG_ID*)ptr;
ptr += sizeof(ALG_ID);
dwBits = *(DWORD*)ptr;
ptr += dwIncrement;
dwNameLen = *(DWORD*)ptr;
ptr += dwIncrement;
strncpy(szName, (char*)ptr, __min(dwNameLen,99));szName[__min(dwNameLen,99)]=0;
//獲取演算法型別
switch(GET_ALG_CLASS(aiAlgid)) {
case ALG_CLASS_DATA_ENCRYPT:
pszAlgType = "加密";
break;
case ALG_CLASS_HASH:
pszAlgType = "哈希";
break;
case ALG_CLASS_KEY_EXCHANGE:
pszAlgType = "交換";
break;
case ALG_CLASS_SIGNATURE:
pszAlgType = "簽名";
break;
default:
pszAlgType = "未知";
break;
}
//列印演算法資訊
printf("%8.8xh %4d %4s %4d %s\n",
aiAlgid, dwBits, pszAlgType, dwNameLen, szName);
} else {
fMore = FALSE;
}
}
Wait(TEXT("\n按Enter繼續"));
if(!(CryptReleaseContext(hProv, 0))) {
HandleError(TEXT("呼叫CryptReleaseContext時出錯\n"));
}
if(GetLastError() == ERROR_NO_MORE_ITEMS) {
_tprintf(TEXT("\n程式成功執行完畢\n"));
} else {
HandleError(TEXT("讀取演算法資訊時出錯"));
}
return 0;
}
void HandleError(TCHAR* s) {
_tprintf(TEXT("程式運行出現錯誤.\n"));
_tprintf(TEXT("%s\n"),s);
_tprintf(TEXT("錯誤代碼%x\n."), GetLastError());
_tprintf(TEXT("程式終止.\n"));
exit(1);
}
void Wait(TCHAR* s) {
char x;
_tprintf(s);
x = getchar();
}
//列舉可用的CSP提供者型別
//CSP提供者型別 CSP提供者型別名稱
//_____________ __________________________________________________
// 1 RSA Full (Signature and Key Exchange)
// 3 DSS Signature
// 12 RSA SChannel
// 13 DSS Signature with Diffie-Hellman Key Exchange
// 18 Diffie-Hellman SChannel
// 24 RSA Full and AES
//
//列舉支持的密碼演算法
//演算法ID 位數 型別 長度 演算法名稱
//_________ ____ ____ ____ ____________________
//00006602h 128 加密 4 RC2
//00006801h 128 加密 4 RC4
//00006601h 56 加密 4 DES
//00006609h 112 加密 13 3DES TWO KEY
//00006603h 168 加密 5 3DES
//00008004h 160 哈希 6 SHA-1
//00008001h 128 哈希 4 MD2
//00008002h 128 哈希 4 MD4
//00008003h 128 哈希 4 MD5
//00008008h 288 哈希 12 SSL3 SHAMD5
//00008005h 0 哈希 4 MAC
//00002400h 1024 簽名 9 RSA_SIGN
//0000a400h 1024 交換 9 RSA_KEYX
//00008009h 0 哈希 5 HMAC
//
//按Enter繼續
//
//程式成功執行完畢
//
uj5u.com熱心網友回復:
8樓,最后那兒……HMAC 的位數怎么是0呢?
uj5u.com熱心網友回復:
可能因為偶用的電腦是十年前公司給配的Windows Server 2003吧。
uj5u.com熱心網友回復:
##############################################################Keyed-Hash Message Authentication Code (HMAC)
Hashlen = 512
##############################################################
Key length = 128
Tag length = 64
Input Date:
"Sample message for keylen=blocklen"
Text is
5361 6D706C65 206D6573
73616765 20666F72 206B6579 6C656E3D 626C6F63 6B6C656E
Key is
00010203 04050607
08090A0B 0C0D0E0F 10111213 14151617 18191A1B 1C1D1E1F
20212223 24252627 28292A2B 2C2D2E2F 30313233 34353637
38393A3B 3C3D3E3F 40414243 44454647 48494A4B 4C4D4E4F
50515253 54555657 58595A5B 5C5D5E5F 60616263 64656667
68696A6B 6C6D6E6F 70717273 74757677 78797A7B 7C7D7E7F
--------------------------------------------------------------
K0 is
00010203 04050607
08090A0B 0C0D0E0F 10111213 14151617 18191A1B 1C1D1E1F
20212223 24252627 28292A2B 2C2D2E2F 30313233 34353637
38393A3B 3C3D3E3F 40414243 44454647 48494A4B 4C4D4E4F
50515253 54555657 58595A5B 5C5D5E5F 60616263 64656667
68696A6B 6C6D6E6F 70717273 74757677 78797A7B 7C7D7E7F
K0^ipad is
36373435 32333031
3E3F3C3D 3A3B3839 26272425 22232021 2E2F2C2D 2A2B2829
16171415 12131011 1E1F1C1D 1A1B1819 06070405 02030001
0E0F0C0D 0A0B0809 76777475 72737071 7E7F7C7D 7A7B7879
66676465 62636061 6E6F6C6D 6A6B6869 56575455 52535051
5E5F5C5D 5A5B5859 46474445 42434041 4E4F4C4D 4A4B4849
Hash((Key^ipad)||text) is
515C86E0 DD382747 A20BDD27 05AF56C1
AB87AA1D A14F3EFD D99A5935 08EC520D 60C10643 A3841B1E
CA7EEFF9 559F5D00 78F93479 58FCA632 1E58769D 15CF3A15
K0 xor opad is
5C5D5E5F 58595A5B
54555657 50515253 4C4D4E4F 48494A4B 44454647 40414243
7C7D7E7F 78797A7B 74757677 70717273 6C6D6E6F 68696A6B
64656667 60616263 1C1D1E1F 18191A1B 14151617 10111213
0C0D0E0F 08090A0B 04050607 00010203 3C3D3E3F 38393A3B
34353637 30313233 2C2D2E2F 28292A2B 24252627 20212223
Hash((K0^opad)||Hash((K0^ipad)||text)) is
FC25E240 658CA785 B7A811A8 D3F7B4CA
48CFA26A 8A366BF2 CD1F836B 05FCB024 BD368530 81811D6C
EA4216EB AD79DA1C FCB95EA4 586B8A0C E356596A 55FB1347
--------------------------------------------------------------
mac is
FC25E240 658CA785 B7A811A8 D3F7B4CA
48CFA26A 8A366BF2 CD1F836B 05FCB024 BD368530 81811D6C
EA4216EB AD79DA1C FCB95EA4 586B8A0C E356596A 55FB1347
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/76790.html
標籤:VBA
