[转]使用Openssl的AES加密算法
转自:http://www.thinkemb.com/wordpress/?p=18
参考:http://blog.csdn.net/shuanyancao/article/details/8985963
Openssl是很常见的C接口的库,个人觉得易用。以下是AES加密的使用备忘。如果你有一定的密码学基础,那么就很好理解。代码是从网上弄下来的(原始地址已经忘记了),然后在尝试的过程中改了一点东西。其它的cbc、cfb、ecb加密方式的用法都是类似的,只是函数名有点区别,就不一一列举了。
【yasi】IV: Initialization Vector,即初始化向量
一、接口简介
- //设置加密密钥,使用字符缓冲区
 - int AES_set_encrypt_key(
 - const unsigned char *userKey,
 - const int bits,
 - AES_KEY *key);
 - //设置解密密钥,同样适用字符缓冲区
 - int AES_set_decrypt_key(
 - const unsigned char *userKey,
 - const int bits,
 - AES_KEY *key);
 - //加解密的接口,通过最后的enc来区分是加密还是解密操作
 - //每次执行AES_cbc_encrypt后,iv(向量)会被更新,
 - //所以需要自己保存它。
 - void AES_cbc_encrypt(
 - const unsigned char *in,
 - unsigned char *out,
 - const unsigned long length,
 - const AES_KEY *key,
 - unsigned char *ivec,
 - const int enc);
 
二、一个简单的Makefile
【yasi】针对CentOS环境,做了修改
- LNK_OPT = -g -L/usr/lib64/ -lssl
 - all:
 - rm -f codec
 - g++ -g aes_codec.cpp -o codec $(LNK_OPT)
 - clean:
 - rm -f codec
 
三、示例代码
- #include <stdio.h>
 - #include <string.h>
 - #include <openssl/aes.h>
 - #include <openssl/rand.h>
 - /* file testaes.cpp */
 - static void hexdump(
 - FILE *f,
 - const char *title,
 - const unsigned char *s,
 - int l)
 - {
 - int n = 0;
 - fprintf(f, "%s", title);
 - for (; n < l; ++n) {
 - if ((n % 16) == 0) {
 - fprintf(f, "\n%04x", n);
 - }
 - fprintf(f, " %02x", s[n]);
 - }
 - fprintf(f, "\n");
 - }
 - int main(int argc, char **argv)
 - {
 - //128bits key.
 - unsigned char rkey[16];
 - //Internal key.
 - AES_KEY key;
 - //Testdata.
 - // [yasi] Make static content instead of random text
 - unsigned char plaintext[AES_BLOCK_SIZE * 4] =
 - {
 - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i',
 - '0', '1', '2', '3', '4', '5', '6', '7', '0', '1', '2', '3', '4', '5', '6', '7',
 - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i',
 - '0', '1', '2', '3', '4', '5', '6', '7', '0', '1', '2', '3', '4', '5', '6', '7'
 - };
 - unsigned char ciphertext[AES_BLOCK_SIZE * 4];
 - unsigned char checktext[AES_BLOCK_SIZE * 4];
 - //Init vector.
 - unsigned char iv[AES_BLOCK_SIZE * 4];
 - //Save vector.
 - unsigned char saved_iv[AES_BLOCK_SIZE * 4];
 - int nr_of_bits = 0;
 - int nr_of_bytes = 0;
 - //Zeror buffer.
 - memset(ciphertext, 0, sizeof ciphertext);
 - memset(checktext, 0, sizeof checktext);
 - //Generate random
 - RAND_pseudo_bytes(rkey, sizeof rkey);
 - RAND_pseudo_bytes(saved_iv, sizeof saved_iv);
 - hexdump(stdout, "== rkey ==",
 - rkey,
 - sizeof(rkey));
 - hexdump(stdout, "== iv ==",
 - saved_iv,
 - sizeof(saved_iv));
 - printf("\n");
 - hexdump(stdout, "== plaintext ==",
 - plaintext,
 - sizeof(plaintext));
 - printf("\n");
 - //Entrypt
 - memcpy(iv, saved_iv, sizeof(iv));
 - nr_of_bits = 8 * sizeof(rkey);
 - AES_set_encrypt_key(rkey, nr_of_bits, &key);
 - nr_of_bytes = sizeof(plaintext);
 - AES_cbc_encrypt(plaintext,
 - ciphertext,
 - nr_of_bytes,
 - &key,
 - iv,
 - AES_ENCRYPT);
 - hexdump(stdout, "== ciphertext ==",
 - ciphertext,
 - sizeof(ciphertext));
 - printf("\n");
 - // [yasi] iv is changed in encryption
 - hexdump(stdout, "== iv changed ==",
 - iv,
 - sizeof(iv));
 - printf("\n");
 - //Decrypt
 - memcpy(iv, saved_iv, sizeof(iv)); // [yasi] without this line, decrypt will fail because iv is changed in encryption
 - nr_of_bits = 8 * sizeof(rkey);
 - AES_set_decrypt_key(rkey, nr_of_bits, &key);
 - nr_of_bytes = sizeof(ciphertext);
 - AES_cbc_encrypt(ciphertext,
 - checktext,
 - nr_of_bytes,
 - &key, iv,
 - AES_DECRYPT);
 - hexdump(stdout, "== checktext ==",
 - checktext,
 - sizeof(checktext));
 - printf("\n");
 - return 0;
 - }
 
【yasi 运行结果】
- [root@ampcommons02 aes-codec]# ./codec
 - == rkey ==
 - 0000 81 ac 9b 38 1c 02 c5 c8 1d 7c a0 3f 87 be f2 c6
 - == iv ==
 - 0000 34 a2 f1 f5 f3 93 76 32 cd 77 ad fb c8 82 f2 1b
 - 0010 f3 cc 51 f6 35 f3 49 8d 44 97 8c 2c 89 50 0d d7
 - 0020 68 21 d7 2f 0a 90 29 c1 dd c9 39 bc 7c 4f 18 2f
 - 0030 04 cc 42 5e 84 8e fe a9 c5 49 00 9f 30 55 94 c0
 - == plaintext ==
 - 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - == ciphertext ==
 - 0000 c4 63 72 29 21 28 7b a2 27 24 4a e4 bb 95 1a d1
 - 0010 b8 13 0e 77 0c 8a a4 09 2f ca 85 43 41 b5 5b d5
 - 0020 a3 60 92 58 5b dd 45 0c e2 62 af f9 43 81 d7 06
 - 0030 41 8e 85 28 3e eb 72 b5 ee 84 8c 27 7e 67 20 f6
 - == iv changed ==
 - 0000 41 8e 85 28 3e eb 72 b5 ee 84 8c 27 7e 67 20 f6
 - 0010 f3 cc 51 f6 35 f3 49 8d 44 97 8c 2c 89 50 0d d7
 - 0020 68 21 d7 2f 0a 90 29 c1 dd c9 39 bc 7c 4f 18 2f
 - 0030 04 cc 42 5e 84 8e fe a9 c5 49 00 9f 30 55 94 c0
 - == checktext ==
 - 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 
可见,encryption之后,IV立即被修改了。所以,为了能正确decrypt,在decrypt时,必须使用先前encrypt时的IV,即代码第98行。
- [root@ampcommons02 aes-codec]# ./codec
 - == rkey ==
 - 0000 29 68 75 4d a5 9e 83 9a ed f8 ec bc 2e b8 09 7e
 - == iv ==
 - 0000 b8 21 09 de 8f 58 6e be 73 be a7 10 fb 91 87 65
 - 0010 65 9c d7 0e 4c 88 d2 65 ae de 0b 49 40 c7 75 df
 - 0020 19 69 53 0b 11 5d ac e7 08 f6 ae df 16 66 e0 13
 - 0030 75 41 f7 bb be 56 a1 dd a7 3e fb 4e 5d 9e e4 a2
 - == plaintext ==
 - 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - == ciphertext ==
 - 0000 5e 85 9c e8 65 d6 3b f9 03 9a a0 b5 78 bd f6 d4
 - 0010 11 70 94 c1 c3 78 9a 1d 12 9a 84 48 3a 70 88 13
 - 0020 d6 b5 bf c6 e8 e1 76 dc 3c b9 b0 4e b9 bb c4 74
 - 0030 35 3d ac fc 29 e3 a0 64 d7 76 ab 76 c7 af dd 39
 - == iv changed ==
 - 0000 35 3d ac fc 29 e3 a0 64 d7 76 ab 76 c7 af dd 39
 - 0010 65 9c d7 0e 4c 88 d2 65 ae de 0b 49 40 c7 75 df
 - 0020 19 69 53 0b 11 5d ac e7 08 f6 ae df 16 66 e0 13
 - 0030 75 41 f7 bb be 56 a1 dd a7 3e fb 4e 5d 9e e4 a2
 - == checktext ==
 - 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 
可见,两次运行,虽然encrypt的明码是一样的,但encrypt出来的结果是不同的。随机明码 改 静态明码 的目的就是为了比较两次encrypt的结果。即,相同的明码用不同的IV做encrypt,结果是不同的。
- [root@ampcommons02 aes-codec]# ./codec
 - == rkey ==
 - 0000 69 ef eb 49 25 5a c2 5e 0d 77 8a cb e6 fe ad 1d
 - == iv ==
 - 0000 8e 05 8c 50 2f 69 9d fb 64 3e cd e6 2d 38 26 1c
 - 0010 6e 21 00 e6 32 3f c6 ca 93 8b c1 e3 47 9a bd 81
 - 0020 d7 e5 0b 63 dc f8 9d 1f 13 49 35 25 70 4e 64 c2
 - 0030 ea 0c d0 78 e7 6c 65 64 41 4d db 2b 50 4d b4 06
 - == plaintext ==
 - 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - == ciphertext ==
 - 0000 a4 ed ba 4b 9f e9 74 bd 6d f6 03 76 79 9f 17 4f
 - 0010 0c cd f3 b8 da 69 44 81 c9 f2 8b 03 83 0d 9d 77
 - 0020 12 48 ea 46 3f eb 58 fd 48 c5 cc 2d 74 6c 99 4f
 - 0030 93 bd 0d 06 f3 55 40 11 cb e7 d4 29 3b 8f 15 76
 - == iv changed ==
 - 0000 93 bd 0d 06 f3 55 40 11 cb e7 d4 29 3b 8f 15 76
 - 0010 6e 21 00 e6 32 3f c6 ca 93 8b c1 e3 47 9a bd 81
 - 0020 d7 e5 0b 63 dc f8 9d 1f 13 49 35 25 70 4e 64 c2
 - 0030 ea 0c d0 78 e7 6c 65 64 41 4d db 2b 50 4d b4 06
 - == checktext ==
 - 0000 7c da e2 32 b9 5a ba 83 ce bb 7a ab 73 d1 54 03
 - 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 - 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
 - 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
 
可见,decrypt时使用和encrypt时不同的IV,不能正确decrypt出先前的明码。
- #ifndef ALGO_AES_H
 - #define ALGO_AES_H
 - int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
 - unsigned char *iv, unsigned char *ciphertext);
 - int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
 - unsigned char *iv, unsigned char *plaintext);
 - #endif
 
algo_aes.c
- #include <stdlib.h>
 - #include <stdio.h>
 - #include "algo_aes.h"
 - #include <openssl/evp.h>
 - void handleErrors(void)
 - {
 - ERR_print_errors_fp(stderr);
 - abort();
 - }
 - int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
 - unsigned char *iv, unsigned char *ciphertext)
 - {
 - EVP_CIPHER_CTX *ctx;
 - int len;
 - int ciphertext_len;
 - /* Create and initialise the context */
 - if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
 - /* Initialise the encryption operation. IMPORTANT - ensure you use a key
 - * and IV size appropriate for your cipher
 - * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 - * IV size for *most* modes is the same as the block size. For AES this
 - * is 128 bits */
 - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
 - handleErrors();
 - /* Provide the message to be encrypted, and obtain the encrypted output.
 - * EVP_EncryptUpdate can be called multiple times if necessary
 - */
 - if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
 - handleErrors();
 - ciphertext_len = len;
 - /* Finalise the encryption. Further ciphertext bytes may be written at
 - * this stage.
 - */
 - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
 - ciphertext_len += len;
 - /* Clean up */
 - EVP_CIPHER_CTX_free(ctx);
 - return ciphertext_len;
 - }
 - int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
 - unsigned char *iv, unsigned char *plaintext)
 - {
 - EVP_CIPHER_CTX *ctx;
 - int len;
 - int plaintext_len;
 - /* Create and initialise the context */
 - if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
 - /* Initialise the decryption operation. IMPORTANT - ensure you use a key
 - * and IV size appropriate for your cipher
 - * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 - * IV size for *most* modes is the same as the block size. For AES this
 - * is 128 bits */
 - if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
 - handleErrors();
 - /* Provide the message to be decrypted, and obtain the plaintext output.
 - * EVP_DecryptUpdate can be called multiple times if necessary
 - */
 - if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
 - handleErrors();
 - plaintext_len = len;
 - /* Finalise the decryption. Further plaintext bytes may be written at
 - * this stage.
 - */
 - if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
 - plaintext_len += len;
 - /* Clean up */
 - EVP_CIPHER_CTX_free(ctx);
 - return plaintext_len;
 - }
 
main.c
- #include "algo_aes.h"
 - #include <stdio.h>
 - #include <string.h>
 - //#include <openssl/evp.h>
 - int main(int arc, char *argv[])
 - {
 - /* Set up the key and iv. Do I need to say to not hard code these in a
 - * real application? :-)
 - */
 - /* A 256 bit key */
 - unsigned char *key = "01234567890123456789012345678901";
 - /* A 128 bit IV */
 - unsigned char *iv = "01234567890123456";
 - /* Message to be encrypted */
 - unsigned char *plaintext =
 - "The quick brown fox jumps over the lazy dog1234";
 - /* Buffer for ciphertext. Ensure the buffer is long enough for the
 - * ciphertext which may be longer than the plaintext, dependant on the
 - * algorithm and mode
 - */
 - unsigned char ciphertext[64];
 - /* Buffer for the decrypted text */
 - unsigned char decryptedtext[64];
 - int decryptedtext_len, ciphertext_len;
 - /* Initialise the library */
 - /* ERR_load_crypto_strings();
 - OpenSSL_add_all_algorithms();
 - OPENSSL_config(NULL);*/
 - printf("Plaintext is:\n%s~\n", plaintext);
 - /* Encrypt the plaintext */
 - ciphertext_len = encrypt(plaintext, strlen(plaintext), key, iv,
 - ciphertext);
 - /* Do something useful with the ciphertext here */
 - printf("Ciphertext is %d bytes long:\n", ciphertext_len);
 - BIO_dump_fp(stdout, ciphertext, ciphertext_len);
 - /* Decrypt the ciphertext */
 - decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
 - decryptedtext);
 - /* Add a NULL terminator. We are expecting printable text */
 - decryptedtext[decryptedtext_len] = '\0';
 - /* Show the decrypted text */
 - printf("Decrypted text is:\n");
 - printf("%s~\n", decryptedtext);
 - /* Clean up */
 - EVP_cleanup();
 - ERR_free_strings();
 - return 0;
 - }
 
Mekefile:
- OBJ_DIR = ./obj
 - BIN_DIR = ./bin
 - SRC_DIR = ./
 - OBJS = \
 - $(OBJ_DIR)/algo_aes.o \
 - $(OBJ_DIR)/main.o
 - TARGET = $(BIN_DIR)/main
 - INC_OPT = -I./
 - LNK_OPT = -lssl
 - $(TARGET) : clean chkobjdir chkbindir $(OBJS)
 - gcc -g -o $@ $(OBJS) $(LNK_OPT)
 - $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
 - gcc -g $(INC_OPT) -c -o $@ $<
 - chkobjdir :
 - @if test ! -d $(OBJ_DIR) ; \
 - then \
 - mkdir $(OBJ_DIR) ; \
 - fi
 - chkbindir :
 - @if test ! -d $(BIN_DIR) ; \
 - then \
 - mkdir $(BIN_DIR) ; \
 - fi
 - clean :
 - -rm -f $(TARGET)
 - -rm -rf $(OBJ_DIR)
 
- Plaintext is:
 - The quick brown fox jumps over the lazy dog1234~
 - Ciphertext is 48 bytes long:
 - 0000 - e0 6f 63 a7 11 e8 b7 aa-9f 94 40 10 7d 46 80 a1 .oc.......@.}F..
 - 0010 - 17 99 43 80 ea 31 d2 a2-99 b9 53 02 d4 39 b9 70 ..C..1....S..9.p
 - 0020 - e9 29 d5 a8 03 bd 71 31-b8 c3 6f 3d 39 3a 3d 3d .)....q1..o=9:==
 - Decrypted text is:
 - The quick brown fox jumps over the lazy dog1234~
 
注意:(参考)
AES算法的块(block)的长度固定为16字节。假设一个字符串在AES加密前的长度为cleanLen,加密后的长度为cipherLen,则二者有下面的关系,其中的“/”是整除。
cipherLen = (clearLen/16 + 1) * 16
| clearLen | cipherLen | 
|---|---|
| 47 | 48 | 
| 48 | 64 | 
| 49 | 64 | 
[转]使用Openssl的AES加密算法的更多相关文章
- 使用Openssl的AES加密算法
		
原文链接: http://blog.csdn.net/yasi_xi/article/details/13997337 Openssl是很常见的C接口的库,个人觉得易用.以下是AES加密的使用备忘.如 ...
 - openssl之aes加密(源码分析 AES_encrypt 与 AES_cbc_encrypt ,加密模式)
		
首先要了解AES加密是什么,以及几种加密模式的区别.之后才是编程.具体的编程案例,在下面的链接. openssl之aes加密(AES_cbc_encrypt 与 AES_encrypt 的编程案例) ...
 - php RSA和AES加密算法
		
一.RSA加密 RSA只说PHP中的应用,详细的算法原理解释,请自行百度,或者参考(RSA加密算法-详细解释以及公钥加密为什么每次都不一样) 总结:公钥加密.私钥解密.私钥签名.公钥验签. 注意: 1 ...
 - AES加密算法C++实现
		
我从网上下载了一套AES加密算法的C++实现,代码如下: (1)aes.h #ifndef SRC_UTILS_AES_H #define SRC_UTILS_AES_H class AES { pu ...
 - PHP android ios相互兼容的AES加密算法
		
APP项目用户密码传输一直没有用HTTPS,考虑到用户的隐私暂时先用AES对密码加密,以后也可以用于手机端与服务端加密交互. PHP的免费版phpAES项目,手机端解码各种不对. 好不容易找了PHP ...
 - Qt使用AES加密算法对字符串进行加密
		
因工作需要,需要对字符串进行加密处理,在网上找了很长时间,终于找到了一个可以使用的aes加密算法.其源代码采用c++编写而成,但其头文件引用windows.h,经过修改部分代码,将#inc ...
 - Android AES加密算法及事实上现
		
昨天老大叫我看看android加密算法.于是网上找了找,找到了AES加密算法.(当然还有MD5,BASE64什么的http://snowolf.iteye.com/blog/379860这篇文章列举了 ...
 - iOS,Android,.NET通用AES加密算法
		
原文:iOS,Android,.NET通用AES加密算法 这两天为移动App开发API,结果实现加密验证时碰到一大坑.这里不得不吐槽下又臭又硬的iOS,Windows Server无法解密出正确的结果 ...
 - Android AES加密算法,现在实际上
		
昨天,老板让我来看看android加密算法.于是在网上找了找,发现AES加密算法.(当然,MD5,BASE64什么http://snowolf.iteye.com/blog/379860这篇文章列举了 ...
 
随机推荐
- $addToSet   $push
			
结果:
 - Python笔记3-20151027
			
函数的参数 Python的函数定义非常简单,但是灵活度却非常大.除了正常定义的必选参数外,还可以使用默认参数.可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码 ...
 - JSON理解
			
var txt = '{"employees":[' + //多段文字用'+'来组织在一起 '{"firstName":"Bill",&qu ...
 - for计算100以内的奇数和
			
#include "stdio.h" void main() { //for计算100以内的奇数和 步长为1,continue实现 ; ;i<=;i++) { ==) { c ...
 - android Handler vs Timer
			
Handler vs Timer 在我们Android开发过程中,经常需要执行一些短周期的定时任务,这时候有两个选择Timer或者Handler.然而个人认为: Handler 在多个方面比Timer ...
 - CRC的校验原理
			
一.基本原理 CRC检验原理实际上就是在一个p位二进制数据序列之后附加一个r位二进制检验码(序列),从而构成一个总长为n=p+r位的二进制序列:附加在数据序列之后的这个检验码与数据序列的内容之间存在着 ...
 - 初探OpenGL(一)
			
OPenGL ES 1.X 面向功能固定的硬件所涉及并提供加速支持,图形质量以及性能标准. OpenGL ES2.X则提供包括着色器技术在内的全编程3D图形算法.----硬件要求比较高. OpenGL ...
 - 调试MVC项目,不关闭 IIS EXPRESS
			
在VS主面板打开:工具->选项->调试->编辑继续 取消选中[启用"编辑并继续"] 就OK了 (英文版的请对应相应的操作) 不过这是针对所有的调试,如果你想针 ...
 - jquery操作HTML5 的data-*的用法实例分享
			
.mm{width:256px; height:200px;} .mm[data-name='张含韵']{background:url(http://image.zhangxinxu.com/imag ...
 - hdu_3001_Travelling(状压DP)
			
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:给你N个点,M条边,每个点最多走两次,问走完N个点最短的路程为多少. 题解:注意这题有重边 ...