因工作需要、平台轉接。第三方給出的是Java下的Hmac_sha1加密接口方式。
Java部分

Java版源碼 Java版 import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; importpublic class Signature { private static final String HMAC_SHA1 = "HmacSHA1"; /*加密實現,采取加密方式為HMACSHA1 ,返回的是base64處理后的*/ public static String generateSignature(String data, String appSecret) { byte[] byteHMAC = null; try { Mac mac = Mac.getInstance(HMAC_SHA1); SecretKeySpec spec = new SecretKeySpec(appSecret.getBytes(),HMAC_SHA1); mac.init(spec); byteHMAC = mac.doFinal(data.getBytes()); String str1=BytesToStr(byteHMAC); System.out.println("輸出字符數組,未經Base64處理"); System.out.println(str1); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException ignore) { // should never happen } return new String(Base64.encode(byteHMAC)); } /*加密實現,采取加密方式為HMACSHA1 ,返回的是轉化為16進制的*/ public static String getSignature(String data,String key) throws Exception{ byte[] keyBytes=key.getBytes(); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1); Mac mac = Mac.getInstance(HMAC_SHA1); mac.init(signingKey); byte[] rawHmac = mac.doFinal(data.getBytes()); String str1=BytesToStr(rawHmac); System.out.println("輸出字符數組"); System.out.println(str1); StringBuilder sb=new StringBuilder(); for(byte b:rawHmac){ sb.append(byteToHexString(b)); } return sb.toString(); } public static String byteToHexString(byte ib){ char[] Digit={ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; char[] ob=new char[2]; ob[0]=Digit[(ib>>>4)& 0X0f]; ob[1]=Digit[ib & 0X0F]; String s=new String(ob); return s; } public static String BytesToStr(byte[] target) { StringBuffer buf = new StringBuffer(); for (int i = 0, j = target.length; i < j; i++) { buf.append((char) target[i]); } return buf.toString(); } /** * @param value * string to be encoded */ public static String encode(String value) { String encoded = null; try { encoded = URLEncoder.encode(value, "UTF-8"); } catch (UnsupportedEncodingException ignore) { } StringBuffer buf = new StringBuffer(encoded.length()); char focus; for (int i = 0; i < encoded.length(); i++) { focus = encoded.charAt(i); if (focus == '*') { buf.append("%2A"); } else if (focus == '+') { buf.append("%20"); } else if (focus == '%' && (i + 1) < encoded.length() && encoded.charAt(i + 1) == '7' && encoded.charAt(i + 2) == 'E') { buf.append('~'); i += 2; } else { buf.append(focus); } } return buf.toString(); } public static void main(String[] args) throws UnsupportedEncodingException { try { //第一種方式 System.out.println("---------------參數encode----------------------"); String name=generateSignature(("老朋友", "123"); System.out.println("----------加密----------------------"); System.out.println(name); System.out.println("----------壓縮------------------------------"); System.out.println(URLEncoder.encode(name, "UTF-8")); System.out.println("---------------------------------------------"); } catch (UnsupportedEncodingException e) { // TODO 自動生成的 catch 塊 e.printStackTrace(); } try { //第二種方式 可以經過Base64算法原理實現 String name=getSignature("老朋友","123"); System.out.println(name); System.out.println(URLEncoder.encode(name,"UTF-8")); // } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
1、創建Mac對象,初始化加密算法的類型。 測試數據為 ("漸入圍城","123") (“jianruweicheng”,“123”)
Mac mac = Mac.getInstance(HMAC_SHA1); 其中 HMAC_SHA1,覺得應該是枚舉中的一個。
Mac類 其導入的包為jce.jar包, 文件為:jce.src\javax\crypto\Mac.java。
再次追蹤為
sun.security.jca.GetInstance;
This Signature class is used to provide applications the functionality of a digital signature algorithm. Digital signatures are used for authentication and integrity assurance of digital data.(Signature類是用來為應用程序提供的功能的數字簽名算法。數字簽名用於數字數據的認證和完整性保證。)
The signature algorithm can be, among others, the NIST standard DSA, using DSA and SHA-1. The DSA algorithm using the SHA-1 message digest algorithm can be specified as SHA1withDSA. In the case of RSA, there are multiple choices for the message digest algorithm, so the signing algorithm could be specified as, for example, MD2withRSA, MD5withRSA, or SHA1withRSA. The algorithm name must be specified, as there is no default.(谷歌翻譯:。。簽名算法,其中包括NIST標准DSA,使用DSA和SHA-1。可以指定使用SHA-1消息摘要算法的DSA算法SHA1的DSA。在RSA的情況下,有多個選擇的報文摘要算法,所以可以被指定為,例如,MD2withRSA,MD5withRSA,或SHA1withRSA簽名算法。必須指定算法名稱,因為沒有默認的。)
A Signature object can be used to generate and verify digital signatures.(Signature對象可用來生成和驗證數字簽名。)
2、對秘鑰進行加工
SecretKeySpec spec = new SecretKeySpec(appSecret.getBytes(), HMAC_SHA1); 參數String appSecret
追蹤為 :javax.crypto.spec.SecretKeySpec 將原文秘鑰轉為字節數組,只可用於那些沒有其他參數的加密秘鑰。
3、用生成的秘鑰字節數組初始化mac對象。
mac.init(spec);
4、將待加密的文本數組,用mac對象進行處理。
byteHMAC = mac.doFinal(data.getBytes());
/* 經過下列代碼輸出
String str1=BytesToStr(byteHMAC);
System.out.println(str1); 輸出后結果 ᄇiWᅦ[マᄁyワWl■7.Nヨ
*/
5、返回字符串。
5.1 返回經過Base64處理, 對應的 String generateSignature(String data, String appSecret) 方法:
return new String(Base64.encode(byteHMAC));
/*
打印輸出為 smlXx1uPoh55nFdsf+0WNy4BTpY=
*/
5.2 返回轉化為16進制的字符串 對應的 String getSignature(String data,String key) 方法
StringBuilder sb=new StringBuilder();
for(byte b:rawHmac){
sb.append(byteToHexString(b));
}
return sb.toString();
/*
打印輸出為:b26957c75b8fa21e799c576c7fed16372e014e96
*/
由方式2轉化為方式1的方式為 Base64編碼。 每三個字節(byte)轉換為四個字符。以前三位為例 “b26..”
b26-> 1011 0010 0110 ,根據規則 右移2位 00101100|00100110,構成。
計算 第一個為 44(查表為s),第二個為38(查表為m).
對應方式1中經過Base64轉化的 “sm....”
6、主函數 簡化版
public static void main(String[] args) {
String name=generateSignature("漸入圍城","123");
System.out.println(name); // smlXx1uPoh55nFdsf+0WNy4BTpY=
System.out.println(URLEncoder.encode(name, "UTF-8")); //經過Encode處理話,會將'='等字符轉化為 ‘%3D’類似
System.out.println("---------------------------------------------");
String name=getSignature("漸入圍城","123");
System.out.println(name); //打印輸出為:b26957c75b8fa21e799c576c7fed16372e014e96
System.out.println(getSignature("jianruweicheng", "123")); //打印輸出為:71abcdf5b3c4285678787e2b72fed9db11296c27
}
C語言版
HMACSHA1.C文件

#include "sha1.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <memory.h> #ifndef SHA_DIGESTSIZE #define SHA_DIGESTSIZE 20 #endif #ifndef SHA_BLOCKSIZE #define SHA_BLOCKSIZE 64 #endif /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(__u32 state[5], __u8 buffer[64]) { __u32 a, b, c, d, e; typedef union { unsigned char c[64]; __u32 l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF static unsigned char workspace[64]; block = (CHAR64LONG16*)workspace; // NdisMoveMemory(block, buffer, 64); memcpy(block, buffer, 64); #else block = (CHAR64LONG16*)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void SHA1Init(SHA1_CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* Run your data through this. */ void SHA1Update(SHA1_CTX* context, unsigned char* data, __u32 len) { __u32 i, j; j = context->count[0]; if ((context->count[0] += len << 3) < j) context->count[1]++; context->count[1] += (len>>29); j = (j >> 3) & 63; if ((j + len) > 63) { // NdisMoveMemory(&context->buffer[j], data, (i = 64-j)); memcpy(&context->buffer[j], data, (i = 64-j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { SHA1Transform(context->state, &data[i]); } j = 0; } else i = 0; // NdisMoveMemory(&context->buffer[j], &data[i], len - i); memcpy(&context->buffer[j], &data[i], len - i); } /* Add padding and return the message digest. */ void SHA1Final(unsigned char digest[20], SHA1_CTX* context) { __u32 i, j; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1Update(context, (unsigned char *)"\200", 1); while ((context->count[0] & 504) != 448) { SHA1Update(context, (unsigned char *)"\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++) { digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } /* Wipe variables */ i = j = 0; // NdisZeroMemory(context->buffer, 64); // NdisZeroMemory(context->state, 20); // NdisZeroMemory(context->count, 8); // NdisZeroMemory(&finalcount, 8); memset(context->buffer, 0x00, 64); memset(context->state, 0x00, 20); memset(context->count, 0x00, 8); memset(&finalcount, 0x00, 8); #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ SHA1Transform(context->state, context->buffer); #endif } /* Function to print the digest 打印輸出*/ void pr_sha(FILE* fp, unsigned char* s, int t) { int i ; for(i=0;i<t;i++) printf("%02x",s[i]); printf("\n"); } void truncate ( char* d1, /* data to be truncated */ char* d2, /* truncated data */ int len /* length in bytes to keep */ ) { int i ; for (i = 0 ; i < len ; i++) d2[i] = d1[i]; } /* Function to compute the digest 加密算法的主要操作函數 */ void hmac_sha ( char* k, /* 秘鑰 secret key */ int lk, /* 秘鑰長度 length of the key in bytes */ char* d, /* 數據 data */ int ld, /* 數據長度 length of data in bytes */ char* out, /* 輸出的字符串 output buffer, at least "t" bytes */ int t ) { SHA1_CTX ictx, octx ; char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ; char key[SHA_DIGESTSIZE] ; char buf[SHA_BLOCKSIZE] ; int i ; if (lk > SHA_BLOCKSIZE) { SHA1_CTX tctx ; SHA1Init(&tctx) ; SHA1Update(&tctx, k, lk) ; SHA1Final(key, &tctx) ; k = key ; lk = SHA_DIGESTSIZE ; } /**** Inner Digest ****/ SHA1Init(&ictx) ; /* Pad the key for inner digest */ for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x36 ; for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36 ; SHA1Update(&ictx, buf, SHA_BLOCKSIZE) ; SHA1Update(&ictx, d, ld) ; SHA1Final(isha, &ictx) ; /**** Outter Digest ****/ SHA1Init(&octx) ; /* Pad the key for outter digest */ for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x5C ; for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C ; SHA1Update(&octx, buf, SHA_BLOCKSIZE) ; SHA1Update(&octx, isha, SHA_DIGESTSIZE) ; SHA1Final(osha, &octx) ; /* truncate and print the results */ t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t ; truncate(osha, out, t) ; pr_sha(stdout, out, t) ; } int main() { char k[1024],d[1024],out[1024] ; int lk,ld,t; strcpy(d,"jianruweicheng"); strcpy(k,"123"); lk=strlen(k); ld=strlen(d); printf("lk=%d\n",lk); printf("ld=%d\n",ld); t=20; hmac_sha(k,lk,d,ld,out,t); return 0; }
sha1.h文件

#ifndef _IPSEC_SHA1_H_ #define _IPSEC_SHA1_H_ typedef unsigned long __u32; typedef unsigned char __u8; typedef struct { __u32 state[5]; __u32 count[2]; __u8 buffer[64]; } SHA1_CTX; #if defined(rol) #undef rol #endif #define SHA1HANDSOFF #define __LITTLE_ENDIAN #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #ifdef __LITTLE_ENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #else #define blk0(i) block->l[i] #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(__u32 state[5], __u8 buffer[64]); void SHA1Init(SHA1_CTX *context); void SHA1Update(SHA1_CTX *context, unsigned char *data, __u32 len); void SHA1Final(unsigned char digest[20], SHA1_CTX *context); //void hmac_sha1(unsigned char *to_mac,unsigned int to_mac_length, unsigned char *key,unsigned int key_length, unsigned char *out_mac); #endif /* _IPSEC_SHA1_H_ */
測試數據 文本 jianruweicheng 秘鑰 123 結果 為 71abcdf5b3c4285678787e2b72fed9db11296c27
說明:如果用“漸入圍城” 得出的結果 為 3f862d26e2410c4ab43e2d162f39d2e8ff82927a ,與上文Java版 5.2的結果不一樣。
原因:漢字編碼在不同的編譯環境中,有不同的編碼格式。必須轉化為對應的格式(本文統一為 UTF-8)才能與上文Java版的 5.2想匹配。
C++ 版
SHA1類
主要的加密算法核心

SHA1。h #ifndef ___SHA1_HDR___ #define ___SHA1_HDR___ #if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS) #define SHA1_UTILITY_FUNCTIONS #endif #include <memory.h> // Needed for memset and memcpy #ifdef SHA1_UTILITY_FUNCTIONS #include <stdio.h> // Needed for file access and sprintf #include <string.h> // Needed for strcat and strcpy #endif #ifdef _MSC_VER #include <stdlib.h> #endif // You can define the endian mode in your files, without modifying the SHA1 // source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN // in your files, before including the SHA1.h header file. If you don't // define anything, the class defaults to little endian. #if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN) #define SHA1_LITTLE_ENDIAN #endif // Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if // not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it // defaults to wiping. #if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES) #define SHA1_WIPE_VARIABLES #endif ///////////////////////////////////////////////////////////////////////////// // Define 8- and 32-bit variables #ifndef UINT_32 #ifdef _MSC_VER #define UINT_8 unsigned __int8 #define UINT_32 unsigned __int32 #else #define UINT_8 unsigned char #if (ULONG_MAX == 0xFFFFFFFF) #define UINT_32 unsigned long #else #define UINT_32 unsigned int #endif #endif #endif ///////////////////////////////////////////////////////////////////////////// // Declare SHA1 workspace typedef union { UINT_8 c[64]; UINT_32 l[16]; } SHA1_WORKSPACE_BLOCK; class CSHA1 { public: #ifdef SHA1_UTILITY_FUNCTIONS // Two different formats for ReportHash(...) enum { REPORT_HEX = 0, REPORT_DIGIT = 1 }; #endif // Constructor and Destructor CSHA1(); ~CSHA1(); UINT_32 m_state[5]; UINT_32 m_count[2]; UINT_32 __reserved1[1]; UINT_8 m_buffer[64]; UINT_8 m_digest[20]; UINT_32 __reserved2[3]; void Reset(); // Update the hash value void Update(UINT_8 *data, UINT_32 len); #ifdef SHA1_UTILITY_FUNCTIONS bool HashFile(char *szFileName); #endif // Finalize hash and report void Final(); // Report functions: as pre-formatted and raw data #ifdef SHA1_UTILITY_FUNCTIONS void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX); #endif void GetHash(UINT_8 *puDest); private: // Private SHA-1 transformation void Transform(UINT_32 *state, UINT_8 *buffer); // Member variables UINT_8 m_workspace[64]; SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above }; #endif //---------------------------------------------------------- SHA1.CPP #include "SHA1.h" #ifdef SHA1_UTILITY_FUNCTIONS #define SHA1_MAX_FILE_BUFFER 8000 #endif // Rotate x bits to the left #ifndef ROL32 #ifdef _MSC_VER #define ROL32(_val32, _nBits) _rotl(_val32, _nBits) #else #define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits)))) #endif #endif #ifdef SHA1_LITTLE_ENDIAN #define SHABLK0(i) (m_block->l[i] = \ (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF)) #else #define SHABLK0(i) (m_block->l[i]) #endif #define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \ ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1)) // SHA-1 rounds #define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } #define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } #define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); } #define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); } #define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); } CSHA1::CSHA1() { m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace; Reset(); } CSHA1::~CSHA1() { Reset(); } void CSHA1::Reset() { // SHA1 initialization constants m_state[0] = 0x67452301; m_state[1] = 0xEFCDAB89; m_state[2] = 0x98BADCFE; m_state[3] = 0x10325476; m_state[4] = 0xC3D2E1F0; m_count[0] = 0; m_count[1] = 0; } void CSHA1::Transform(UINT_32 *state, UINT_8 *buffer) { // Copy state[] to working vars UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; memcpy(m_block, buffer, 64); // 4 rounds of 20 operations each. Loop unrolled. _R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3); _R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7); _R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11); _R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15); _R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19); _R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23); _R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27); _R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31); _R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35); _R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39); _R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43); _R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47); _R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51); _R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55); _R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59); _R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63); _R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67); _R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71); _R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75); _R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79); // Add the working vars back into state state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; // Wipe variables #ifdef SHA1_WIPE_VARIABLES a = b = c = d = e = 0; #endif } // Use this function to hash in binary data and strings void CSHA1::Update(UINT_8 *data, UINT_32 len) { UINT_32 i, j; j = (m_count[0] >> 3) & 63; if((m_count[0] += len << 3) < (len << 3)) m_count[1]++; m_count[1] += (len >> 29); if((j + len) > 63) { i = 64 - j; memcpy(&m_buffer[j], data, i); Transform(m_state, m_buffer); for(; i + 63 < len; i += 64) Transform(m_state, &data[i]); j = 0; } else i = 0; memcpy(&m_buffer[j], &data[i], len - i); } #ifdef SHA1_UTILITY_FUNCTIONS // Hash in file contents bool CSHA1::HashFile(char *szFileName) { unsigned long ulFileSize, ulRest, ulBlocks; unsigned long i; UINT_8 uData[SHA1_MAX_FILE_BUFFER]; FILE *fIn; if(szFileName == NULL) return false; fIn = fopen(szFileName, "rb"); if(fIn == NULL) return false; fseek(fIn, 0, SEEK_END); ulFileSize = (unsigned long)ftell(fIn); fseek(fIn, 0, SEEK_SET); if(ulFileSize != 0) { ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER; ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER; } else { ulBlocks = 0; ulRest = 0; } for(i = 0; i < ulBlocks; i++) { fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn); Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER); } if(ulRest != 0) { fread(uData, 1, ulRest, fIn); Update((UINT_8 *)uData, ulRest); } fclose(fIn); fIn = NULL; return true; } #endif void CSHA1::Final() { UINT_32 i; UINT_8 finalcount[8]; for(i = 0; i < 8; i++) finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)] >> ((3 - (i & 3)) * 8) ) & 255); // Endian independent Update((UINT_8 *)"\200", 1); while ((m_count[0] & 504) != 448) Update((UINT_8 *)"\0", 1); Update(finalcount, 8); // Cause a SHA1Transform() for(i = 0; i < 20; i++) { m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255); } // Wipe variables for security reasons #ifdef SHA1_WIPE_VARIABLES i = 0; memset(m_buffer, 0, 64); memset(m_state, 0, 20); memset(m_count, 0, 8); memset(finalcount, 0, 8); Transform(m_state, m_buffer); #endif } #ifdef SHA1_UTILITY_FUNCTIONS // Get the final hash as a pre-formatted string void CSHA1::ReportHash(char *szReport, unsigned char uReportType) { unsigned char i; char szTemp[16]; if(szReport == NULL) return; if(uReportType == REPORT_HEX) { sprintf(szTemp, "%02X", m_digest[0]); strcat(szReport, szTemp); for(i = 1; i < 20; i++) { sprintf(szTemp, " %02X", m_digest[i]); strcat(szReport, szTemp); } } else if(uReportType == REPORT_DIGIT) { sprintf(szTemp, "%u", m_digest[0]); strcat(szReport, szTemp); for(i = 1; i < 20; i++) { sprintf(szTemp, " %u", m_digest[i]); strcat(szReport, szTemp); } } else strcpy(szReport, "Error: Unknown report type!"); } #endif // Get the raw message digest void CSHA1::GetHash(UINT_8 *puDest) { memcpy(puDest, m_digest, 20); }
HMac_SHA1類

HMAC_SHA1.H源碼 #ifndef __HMAC_SHA1_H__ #define __HMAC_SHA1_H__ #include "SHA1.h" typedef unsigned char BYTE ; class CHMAC_SHA1 : public CSHA1 { private: BYTE m_ipad[64]; BYTE m_opad[64]; char * szReport ; char * SHA1_Key ; char * AppendBuf1 ; char * AppendBuf2 ; public: enum { SHA1_DIGEST_LENGTH = 20, SHA1_BLOCK_SIZE = 64, HMAC_BUF_LEN = 4096 } ; CHMAC_SHA1() :szReport(new char[HMAC_BUF_LEN]), AppendBuf1(new char[HMAC_BUF_LEN]), AppendBuf2(new char[HMAC_BUF_LEN]), SHA1_Key(new char[HMAC_BUF_LEN]) {} ~CHMAC_SHA1() { delete[] szReport ; delete[] AppendBuf1 ; delete[] AppendBuf2 ; delete[] SHA1_Key ; } void HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest); }; #endif /* __HMAC_SHA1_H__ */ //------------------------------------------------------- HMAC_SHA1.CPP code //****************************************************************************** //* HMAC_SHA1.cpp : Implementation of HMAC SHA1 algorithm //* Comfort to RFC 2104 //* //****************************************************************************** #include <iostream> #include <memory> #include "HMAC_SHA1.h" void CHMAC_SHA1::HMAC_SHA1(BYTE *text, int text_len, BYTE *key, int key_len, BYTE *digest) { memset(SHA1_Key, 0, SHA1_BLOCK_SIZE); /* repeated 64 times for values in ipad and opad */ memset(m_ipad, 0x36, sizeof(m_ipad)); memset(m_opad, 0x5c, sizeof(m_opad)); /* STEP 1 */ if (key_len > SHA1_BLOCK_SIZE) //大於64位 { CSHA1::Reset(); CSHA1::Update((UINT_8 *)key, key_len); CSHA1::Final(); CSHA1::GetHash((UINT_8 *)SHA1_Key);//20 } else memcpy(SHA1_Key, key, key_len); /* STEP 2 */ for (int i=0; i<sizeof(m_ipad); i++) { m_ipad[i] ^= SHA1_Key[i]; } /* STEP 3 */ memcpy(AppendBuf1, m_ipad, sizeof(m_ipad)); memcpy(AppendBuf1 + sizeof(m_ipad), text, text_len); /* STEP 4 */ CSHA1::Reset(); CSHA1::Update((UINT_8 *)AppendBuf1, sizeof(m_ipad) + text_len); CSHA1::Final(); CSHA1::GetHash((UINT_8 *)szReport); /* STEP 5 */ for (int j=0; j<sizeof(m_opad); j++) { m_opad[j] ^= SHA1_Key[j]; } /* STEP 6 */ memcpy(AppendBuf2, m_opad, sizeof(m_opad)); memcpy(AppendBuf2 + sizeof(m_opad), szReport, SHA1_DIGEST_LENGTH); /*STEP 7 */ CSHA1::Reset(); CSHA1::Update((UINT_8 *)AppendBuf2, sizeof(m_opad) + SHA1_DIGEST_LENGTH); CSHA1::Final(); CSHA1::GetHash((UINT_8 *)digest); // char * mu; // CSHA1::ReportHash(mu,REPORT_HEX); }
主要控制加密的主要過程
(1) 在密鑰K后面添加0來創建一個子長為B的字符串。(例如,如果K的字長是20
字節,B=60字節,則K后會加入44個零字節0x00)
(2) 將上一步生成的B字長的字符串與ipad做異或運算。
(3) 將數據流text填充至第二步的結果字符串中。
(4) 用H作用於第三步生成的數據流。
(5) 將第一步生成的B字長字符串與opad做異或運算。
(6) 再將第四步的結果填充進第五步的結果中。
(7) 用H作用於第六步生成的數據流,輸出最終結果
涉及到的字符處理
在C/C++環境中,如果需要加密漢字等字符,與Eclipse中產生同樣的加密結果,則需要先將漢字轉化為UTF-8字符,然后進行加密,在經過Base64處理,輸出。

//-------------------------------------------- // CChineseCode.h //------------------------------------------------- #include <string> #include <stdio.h> #include <windows.h> class CChineseCode { public: CChineseCode(); virtual ~CChineseCode(); // GB2312 轉換成 Unicode static void Gb2312ToUnicode(WCHAR* pOut,char *gbBuffer); //GB2312 轉為 UTF-8 static void GB2312ToUTF_8(CString& pOut,char *pText, int pLen); //轉16進制 static BYTE toHex(const BYTE &x); // 把Unicode 轉換成 GB2312 static void UnicodeToGB2312(char* pOut,unsigned short uData); // Unicode 轉換成UTF-8 static void UnicodeToUTF_8(char* pOut,WCHAR* pText); //URL壓縮 static CString URLEncode(CString sIn); //UTF8壓縮 static CString UTF8_Encode(LPTSTR strUnicode); //UTF-8 轉為 GB2312 static void UTF_8ToGB2312(CString &pOut, char *pText, int pLen); // 把UTF-8轉換成Unicode static void UTF_8ToUnicode(WCHAR* pOut,char *pText); }; //--------------------------------------------- //CChineseCode.cpp //--------------------------------------------- #include "stdafx.h" #include "ChineseCode.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CChineseCode::CChineseCode() { } CChineseCode::~CChineseCode() { } // 把UTF-8轉換成Unicode void CChineseCode::UTF_8ToUnicode(WCHAR* pOut,char *pText) { char* uchar = (char *)pOut; uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F); uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F); return; } // Unicode 轉換成UTF-8 void CChineseCode::UnicodeToUTF_8(char* pOut,WCHAR* pText) { // 注意 WCHAR高低字的順序,低字節在前,高字節在后 char* pchar = (char *)pText; pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4)); pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6); pOut[2] = (0x80 | (pchar[0] & 0x3F)); return; } // 把Unicode 轉換成 GB2312 void CChineseCode::UnicodeToGB2312(char* pOut,unsigned short uData) { WideCharToMultiByte(CP_ACP,NULL,&uData,1,pOut,sizeof(WCHAR),NULL,NULL); return; } // GB2312 轉換成 Unicode void CChineseCode::Gb2312ToUnicode(WCHAR* pOut,char *gbBuffer) { ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,gbBuffer,2,pOut,1); return; } //GB2312 轉為 UTF-8 void CChineseCode::GB2312ToUTF_8(CString& pOut,char *pText, int pLen) { char buf[1024]; char* rst = new char[pLen + (pLen >> 2) + 2]; memset(buf,0,1024); memset(rst,0,pLen + (pLen >> 2) + 2); int i = 0; int j = 0; while(i < pLen) { //如果是英文直接復制就可以 if( *(pText + i) >= 0) { rst[j++] = pText[i++]; } else { WCHAR pbuffer; Gb2312ToUnicode(&pbuffer,pText+i); UnicodeToUTF_8(buf,&pbuffer); unsigned short int tmp = 0; tmp = rst[j] = buf[0]; tmp = rst[j+1] = buf[1]; tmp = rst[j+2] = buf[2]; j += 3; i += 2; } } strcpy(&rst[j],"\0"); //返回結果 pOut = rst; delete []rst; return; } //UTF-8 轉為 GB2312 void CChineseCode::UTF_8ToGB2312(CString &pOut, char *pText, int pLen) { char * newBuf = new char[pLen]; char Ctemp[4]; memset(Ctemp,0,4); int i =0; int j = 0; while(i < pLen) { if(pText[i] > 0) { newBuf[j++] = pText[i++]; } else { WCHAR Wtemp; UTF_8ToUnicode(&Wtemp,pText + i); UnicodeToGB2312(Ctemp,Wtemp); newBuf[j] = Ctemp[0]; newBuf[j + 1] = Ctemp[1]; i += 3; j += 2; } } strcpy(&newBuf[j],"\0"); pOut = newBuf; delete []newBuf; return; } CString CChineseCode::UTF8_Encode(LPTSTR strUnicode) { long TLen ; CString UTF8_EncodeLong ; TLen = CString(strUnicode).GetLength(); if(TLen == 0) { return CString(strUnicode); } long lngBufferSize ; long lngResult ; //Set buffer for longest possible string. lngBufferSize = TLen * 3 + 1 ; char *bytUtf8 = new char[lngBufferSize] ; //Translate using code page 65001(UTF-8). lngResult = WideCharToMultiByte(CP_UTF8, 0, (unsigned short*)strUnicode, TLen, bytUtf8, lngBufferSize, NULL, 0) ; bytUtf8[lngResult] = NULL ; return CString(bytUtf8) ; } /*************************************************************************/ BYTE CChineseCode::toHex(const BYTE &x) { return x > 9 ? x + 55: x + 48; } CString CChineseCode::URLEncode(CString sIn) { CString sOut; const int nLen = sIn.GetLength() + 1; register LPBYTE pOutTmp = NULL; LPBYTE pOutBuf = NULL; register LPBYTE pInTmp = NULL; LPBYTE pInBuf =(LPBYTE)sIn.GetBuffer(nLen); BYTE b = 0; //alloc out buffer pOutBuf = (LPBYTE)sOut.GetBuffer(nLen*3 - 2);//new BYTE [nLen * 3]; if(pOutBuf) { pInTmp = pInBuf; pOutTmp = pOutBuf; // do encoding while (*pInTmp) { if(isalnum(*pInTmp)) *pOutTmp++ = *pInTmp; else if(isspace(*pInTmp)) *pOutTmp++ = '+'; else // if(*pInTmp<=127) // *pOutTmp++ = *pInTmp; // else { *pOutTmp++ = '%'; *pOutTmp++ = toHex(*pInTmp>>4); *pOutTmp++ = toHex(*pInTmp%16); } pInTmp++; } *pOutTmp = '\0'; //sOut=pOutBuf; //delete [] pOutBuf; sOut.ReleaseBuffer(); } sIn.ReleaseBuffer(); return sOut; }
Base64源碼

//Base64.h #include <string> using namespace std; class ZBase64 { public: /*編碼 DataByte [in]輸入的數據長度,以字節為單位 */ string Encode(const unsigned char* Data,int DataByte); /*解碼 DataByte [in]輸入的數據長度,以字節為單位 OutByte [out]輸出的數據長度,以字節為單位,請不要通過返回值計算 輸出數據的長度 */ string Decode(const char* Data,int DataByte,int& OutByte); }; //-- --Base64.cpp #include "stdAfx.h" #include "ZBase64.h" string ZBase64::Encode(const unsigned char* Data,int DataByte) { //編碼表 const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //返回值 string strEncode; unsigned char Tmp[4]={0}; int LineLength=0; for(int i=0;i<(int)(DataByte / 3);i++) { Tmp[1] = *Data++; Tmp[2] = *Data++; Tmp[3] = *Data++; strEncode+= EncodeTable[Tmp[1] >> 2]; strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F]; strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F]; strEncode+= EncodeTable[Tmp[3] & 0x3F]; if(LineLength+=4,LineLength==76) {strEncode+="\r\n";LineLength=0;} } //對剩余數據進行編碼 int Mod=DataByte % 3; if(Mod==1) { Tmp[1] = *Data++; strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2]; strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)]; strEncode+= "=="; } else if(Mod==2) { Tmp[1] = *Data++; Tmp[2] = *Data++; strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2]; strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)]; strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)]; strEncode+= "="; } return strEncode; } string ZBase64::Decode(const char* Data,int DataByte,int& OutByte) { //解碼表 const char DecodeTable[] = { , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, , // '+' , 0, 0, , // '/' , 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9' , 0, 0, 0, 0, 0, 0, , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, , 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z' , 0, 0, 0, 0, 0, , 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, , 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z' }; //返回值 string strDecode; int nValue; int i= 0; while (i < DataByte) { if (*Data != '\r' && *Data!='\n') { nValue = DecodeTable[*Data++] << 18; nValue += DecodeTable[*Data++] << 12; strDecode+=(nValue & 0x00FF0000) >> 16; OutByte++; if (*Data != '=') { nValue += DecodeTable[*Data++] << 6; strDecode+=(nValue & 0x0000FF00) >> 8; OutByte++; if (*Data != '=') { nValue += DecodeTable[*Data++]; strDecode+=nValue & 0x000000FF; OutByte++; } } i += 4; } else// 回車換行,跳過 { Data++; i++; } } return strDecode; }
將“漸入圍城” 字符轉換,經過秘鑰 “123” 加密,再過Base64處理,輸出。
PS:MSDN中,看到了Hmac_sha1加密算法的影子,搞了會沒有搞明白,然后就舍棄了。
參考
1、http://www.cnblogs.com/skyaspnet/archive/2010/10/06/1844616.html DSA算法的理論,實現,以及在破解中的應用
2、http://chenlingreen.iteye.com/blog/91847 Java加密算法
3、http://kb.cnblogs.com/page/166471/ Base 64 Encoding 編碼
4、http://www.iteye.com/topic/604440 HMAC-SHA1的java源代碼實現
5、http://www.cnblogs.com/phinecos/archive/2008/10/10/1308272.html Base64編解碼(C++版)
6、http://www.codeproject.com/Articles/22118/C-Class-Implementation-of-HMAC-SHA C++ Class Implementation of HMAC-SHA
7、http://www.cnblogs.com/kenkofox/archive/2010/05/10/1731910.html URL相關編碼