因工作需要、平台转接。第三方给出的是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相关编码