I2C toy code
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

398 linhas
12 KiB

  1. /* LibTomCrypt, modular cryptographic library -- Tom St Denis
  2. *
  3. * LibTomCrypt is a library that provides various cryptographic
  4. * algorithms in a highly modular and flexible manner.
  5. *
  6. * The library is free for all purposes without any express
  7. * guarantee it works.
  8. */
  9. /*
  10. * Demo to do the rough equivalent of:
  11. *
  12. * openssl enc -aes-256-cbc -pass pass:foobar -in infile -out outfile -p
  13. *
  14. * Compilation:
  15. *
  16. * $(CC) -I /path/to/headers -L .../libs \
  17. * -o openssl-enc \
  18. * openssl-enc.c -ltomcrypt
  19. *
  20. * Usage:
  21. *
  22. * ./openssl-enc <enc|dec> infile outfile "passphrase" [salt]
  23. *
  24. * If provided, the salt must be EXACTLY a 16-char hex string.
  25. *
  26. * Demo is an example of:
  27. *
  28. * - (When decrypting) yanking salt out of the OpenSSL "Salted__..." header
  29. * - OpenSSL-compatible key derivation (in OpenSSL's modified PKCS#5v1 approach)
  30. * - Grabbing an Initialization Vector from the key generator
  31. * - Performing simple block encryption using AES
  32. * - PKCS#7-type padding (which hopefully can get ripped out of this demo and
  33. * made a libtomcrypt thing someday).
  34. *
  35. * This program is free for all purposes without any express guarantee it
  36. * works. If you really want to see a license here, assume the WTFPL :-)
  37. *
  38. * BJ Black, bblack@barracuda.com, https://wjblack.com
  39. *
  40. * BUGS:
  41. * Passing a password on a command line is a HORRIBLE idea. Don't use
  42. * this program for serious work!
  43. */
  44. #include <tomcrypt.h>
  45. #ifndef LTC_RIJNDAEL
  46. #error Cannot compile this demo; Rijndael (AES) required
  47. #endif
  48. #ifndef LTC_CBC_MODE
  49. #error Cannot compile this demo; CBC mode required
  50. #endif
  51. #ifndef LTC_PKCS_5
  52. #error Cannot compile this demo; PKCS5 required
  53. #endif
  54. #ifndef LTC_RNG_GET_BYTES
  55. #error Cannot compile this demo; random generator required
  56. #endif
  57. #ifndef LTC_MD5
  58. #error Cannot compile this demo; MD5 required
  59. #endif
  60. /* OpenSSL by default only runs one hash round */
  61. #define OPENSSL_ITERATIONS 1
  62. /* Use aes-256-cbc, so 256 bits of key, 128 of IV */
  63. #define KEY_LENGTH (256>>3)
  64. #define IV_LENGTH (128>>3)
  65. /* PKCS#5v1 requires exactly an 8-byte salt */
  66. #define SALT_LENGTH 8
  67. /* The header OpenSSL puts on an encrypted file */
  68. static char salt_header[] = { 'S', 'a', 'l', 't', 'e', 'd', '_', '_' };
  69. #include <errno.h>
  70. #include <stdio.h>
  71. #include <string.h>
  72. /* A simple way to handle the possibility that a block may increase in size
  73. after padding. */
  74. union paddable {
  75. unsigned char unpad[1024];
  76. unsigned char pad[1024+MAXBLOCKSIZE];
  77. };
  78. /*
  79. * Print usage and exit with a bad status (and perror() if any errno).
  80. *
  81. * Input: argv[0] and the error string
  82. * Output: <no return>
  83. * Side Effects: print messages and barf (does exit(3))
  84. */
  85. void barf(char *pname, char *err)
  86. {
  87. printf("Usage: %s <enc|dec> infile outfile [salt]\n", pname);
  88. printf("\n");
  89. printf(" # encrypts infile->outfile, random salt\n");
  90. printf(" %s enc infile outfile \"passphrase\"\n", pname);
  91. printf("\n");
  92. printf(" # encrypts infile->outfile, salt from cmdline\n");
  93. printf(" %s enc infile outfile pass 0123456789abcdef\n", pname);
  94. printf("\n");
  95. printf(" # decrypts infile->outfile, pulls salt from infile\n");
  96. printf(" %s dec infile outfile pass\n", pname);
  97. printf("\n");
  98. printf(" # decrypts infile->outfile, salt specified\n");
  99. printf(" # (don't try to read the salt from infile)\n");
  100. printf(" %s dec infile outfile pass 0123456789abcdef"
  101. "\n", pname);
  102. printf("\n");
  103. printf("Application Error: %s\n", err);
  104. if(errno)
  105. perror(" System Error");
  106. exit(-1);
  107. }
  108. /*
  109. * Parse a salt value passed in on the cmdline.
  110. *
  111. * Input: string passed in and a buf to put it in (exactly 8 bytes!)
  112. * Output: CRYPT_OK if parsed OK, CRYPT_ERROR if not
  113. * Side Effects: none
  114. */
  115. int parse_hex_salt(unsigned char *in, unsigned char *out)
  116. {
  117. int idx;
  118. for(idx=0; idx<SALT_LENGTH; idx++)
  119. if(sscanf((char*)in+idx*2, "%02hhx", out+idx) != 1)
  120. return CRYPT_ERROR;
  121. return CRYPT_OK;
  122. }
  123. /*
  124. * Parse the Salted__[+8 bytes] from an OpenSSL-compatible file header.
  125. *
  126. * Input: file to read from and a to put the salt in (exactly 8 bytes!)
  127. * Output: CRYPT_OK if parsed OK, CRYPT_ERROR if not
  128. * Side Effects: infile's read pointer += 16
  129. */
  130. int parse_openssl_header(FILE *in, unsigned char *out)
  131. {
  132. unsigned char tmp[SALT_LENGTH];
  133. if(fread(tmp, 1, sizeof(tmp), in) != sizeof(tmp))
  134. return CRYPT_ERROR;
  135. if(memcmp(tmp, salt_header, sizeof(tmp)))
  136. return CRYPT_ERROR;
  137. if(fread(tmp, 1, sizeof(tmp), in) != sizeof(tmp))
  138. return CRYPT_ERROR;
  139. memcpy(out, tmp, sizeof(tmp));
  140. return CRYPT_OK;
  141. }
  142. /*
  143. * Dump a hexed stream of bytes (convenience func).
  144. *
  145. * Input: buf to read from, length
  146. * Output: none
  147. * Side Effects: bytes printed as a hex blob, no lf at the end
  148. */
  149. void dump_bytes(unsigned char *in, unsigned long len)
  150. {
  151. unsigned long idx;
  152. for(idx=0; idx<len; idx++)
  153. printf("%02hhX", *(in+idx));
  154. }
  155. /*
  156. * Pad or unpad a message using PKCS#7 padding.
  157. * Padding will add 1-(blocksize) bytes and unpadding will remove that amount.
  158. * Set is_padding to 1 to pad, 0 to unpad.
  159. *
  160. * Input: paddable buffer, size read, block length of cipher, mode
  161. * Output: number of bytes after padding resp. after unpadding
  162. * Side Effects: none
  163. */
  164. size_t pkcs7_pad(union paddable *buf, size_t nb, int block_length,
  165. int is_padding)
  166. {
  167. unsigned char padval;
  168. off_t idx;
  169. if(is_padding) {
  170. /* We are PADDING this block (and therefore adding bytes) */
  171. /* The pad value in PKCS#7 is the number of bytes remaining in
  172. the block, so for a 16-byte block and 3 bytes left, it's
  173. 0x030303. In the oddball case where nb is an exact multiple
  174. multiple of block_length, set the padval to blocksize (i.e.
  175. add one full block) */
  176. padval = (unsigned char) (block_length - (nb % block_length));
  177. padval = padval ? padval : block_length;
  178. memset(buf->pad+nb, padval, padval);
  179. return nb+padval;
  180. } else {
  181. /* We are UNPADDING this block (and removing bytes)
  182. We really just need to verify that the pad bytes are correct,
  183. so start at the end of the string and work backwards. */
  184. /* Figure out what the padlength should be by looking at the
  185. last byte */
  186. idx = nb-1;
  187. padval = buf->pad[idx];
  188. /* padval must be nonzero and <= block length */
  189. if(padval <= 0 || padval > block_length)
  190. return 0;
  191. /* First byte's accounted for; do the rest */
  192. idx--;
  193. while(idx >= (off_t)(nb-padval))
  194. if(buf->pad[idx] != padval)
  195. return 0;
  196. else
  197. idx--;
  198. /* If we got here, the pad checked out, so return a smaller
  199. number of bytes than nb (basically where we left off+1) */
  200. return idx+1;
  201. }
  202. }
  203. /*
  204. * Perform an encrypt/decrypt operation to/from files using AES+CBC+PKCS7 pad.
  205. * Set encrypt to 1 to encrypt, 0 to decrypt.
  206. *
  207. * Input: in/out files, key, iv, and mode
  208. * Output: CRYPT_OK if no error
  209. * Side Effects: bytes slurped from infile, pushed to outfile, fds updated.
  210. */
  211. int do_crypt(FILE *infd, FILE *outfd, unsigned char *key, unsigned char *iv,
  212. int encrypt)
  213. {
  214. union paddable inbuf, outbuf;
  215. int cipher, ret;
  216. symmetric_CBC cbc;
  217. size_t nb;
  218. /* Register your cipher! */
  219. cipher = register_cipher(&aes_desc);
  220. if(cipher == -1)
  221. return CRYPT_INVALID_CIPHER;
  222. /* Start a CBC session with cipher/key/val params */
  223. ret = cbc_start(cipher, iv, key, KEY_LENGTH, 0, &cbc);
  224. if( ret != CRYPT_OK )
  225. return -1;
  226. do {
  227. /* Get bytes from the source */
  228. nb = fread(inbuf.unpad, 1, sizeof(inbuf.unpad), infd);
  229. if(!nb)
  230. return encrypt ? CRYPT_OK : CRYPT_ERROR;
  231. /* Barf if we got a read error */
  232. if(ferror(infd))
  233. return CRYPT_ERROR;
  234. if(encrypt) {
  235. /* We're encrypting, so pad first (if at EOF) and then
  236. crypt */
  237. if(feof(infd))
  238. nb = pkcs7_pad(&inbuf, nb,
  239. aes_desc.block_length, 1);
  240. ret = cbc_encrypt(inbuf.pad, outbuf.pad, nb, &cbc);
  241. if(ret != CRYPT_OK)
  242. return ret;
  243. } else {
  244. /* We're decrypting, so decrypt and then unpad if at
  245. EOF */
  246. ret = cbc_decrypt(inbuf.unpad, outbuf.unpad, nb, &cbc);
  247. if( ret != CRYPT_OK )
  248. return ret;
  249. if( feof(infd) )
  250. nb = pkcs7_pad(&outbuf, nb,
  251. aes_desc.block_length, 0);
  252. if(nb == 0)
  253. /* The file didn't decrypt correctly */
  254. return CRYPT_ERROR;
  255. }
  256. /* Push bytes to outfile */
  257. if(fwrite(outbuf.unpad, 1, nb, outfd) != nb)
  258. return CRYPT_ERROR;
  259. } while(!feof(infd));
  260. /* Close up */
  261. cbc_done(&cbc);
  262. return CRYPT_OK;
  263. }
  264. /* Convenience macro for the various barfable places below */
  265. #define BARF(a) { \
  266. if(infd) fclose(infd); \
  267. if(outfd) { fclose(outfd); remove(argv[3]); } \
  268. barf(argv[0], a); \
  269. }
  270. /*
  271. * The main routine. Mostly validate cmdline params, open files, run the KDF,
  272. * and do the crypt.
  273. */
  274. int main(int argc, char *argv[]) {
  275. unsigned char salt[SALT_LENGTH];
  276. FILE *infd = NULL, *outfd = NULL;
  277. int encrypt = -1;
  278. int hash = -1;
  279. int ret;
  280. unsigned char keyiv[KEY_LENGTH + IV_LENGTH];
  281. unsigned long keyivlen = (KEY_LENGTH + IV_LENGTH);
  282. unsigned char *key, *iv;
  283. /* Check proper number of cmdline args */
  284. if(argc < 5 || argc > 6)
  285. BARF("Invalid number of arguments");
  286. /* Check proper mode of operation */
  287. if (!strncmp(argv[1], "enc", 3))
  288. encrypt = 1;
  289. else if(!strncmp(argv[1], "dec", 3))
  290. encrypt = 0;
  291. else
  292. BARF("Bad command name");
  293. /* Check we can open infile/outfile */
  294. infd = fopen(argv[2], "rb");
  295. if(infd == NULL)
  296. BARF("Could not open infile");
  297. outfd = fopen(argv[3], "wb");
  298. if(outfd == NULL)
  299. BARF("Could not open outfile");
  300. /* Get the salt from wherever */
  301. if(argc == 6) {
  302. /* User-provided */
  303. if(parse_hex_salt((unsigned char*) argv[5], salt) != CRYPT_OK)
  304. BARF("Bad user-specified salt");
  305. } else if(!strncmp(argv[1], "enc", 3)) {
  306. /* Encrypting; get from RNG */
  307. if(rng_get_bytes(salt, sizeof(salt), NULL) != sizeof(salt))
  308. BARF("Not enough random data");
  309. } else {
  310. /* Parse from infile (decrypt only) */
  311. if(parse_openssl_header(infd, salt) != CRYPT_OK)
  312. BARF("Invalid OpenSSL header in infile");
  313. }
  314. /* Fetch the MD5 hasher for PKCS#5 */
  315. hash = register_hash(&md5_desc);
  316. if(hash == -1)
  317. BARF("Could not register MD5 hash");
  318. /* Set things to a sane initial state */
  319. zeromem(keyiv, sizeof(keyiv));
  320. key = keyiv + 0; /* key comes first */
  321. iv = keyiv + KEY_LENGTH; /* iv comes next */
  322. /* Run the key derivation from the provided passphrase. This gets us
  323. the key and iv. */
  324. ret = pkcs_5_alg1_openssl((unsigned char*)argv[4], strlen(argv[4]), salt,
  325. OPENSSL_ITERATIONS, hash, keyiv, &keyivlen );
  326. if(ret != CRYPT_OK)
  327. BARF("Could not derive key/iv from passphrase");
  328. /* Display the salt/key/iv like OpenSSL cmdline does when -p */
  329. printf("salt="); dump_bytes(salt, sizeof(salt)); printf("\n");
  330. printf("key="); dump_bytes(key, KEY_LENGTH); printf("\n");
  331. printf("iv ="); dump_bytes(iv, IV_LENGTH ); printf("\n");
  332. /* If we're encrypting, write the salt header as OpenSSL does */
  333. if(!strncmp(argv[1], "enc", 3)) {
  334. if(fwrite(salt_header, 1, sizeof(salt_header), outfd) !=
  335. sizeof(salt_header) )
  336. BARF("Error writing salt header to outfile");
  337. if(fwrite(salt, 1, sizeof(salt), outfd) != sizeof(salt))
  338. BARF("Error writing salt to outfile");
  339. }
  340. /* At this point, the files are open, the salt has been figured out,
  341. and we're ready to pump data through crypt. */
  342. /* Do the crypt operation */
  343. if(do_crypt(infd, outfd, key, iv, encrypt) != CRYPT_OK)
  344. BARF("Error during crypt operation");
  345. /* Clean up */
  346. fclose(infd); fclose(outfd);
  347. return 0;
  348. }
  349. /* ref: $Format:%D$ */
  350. /* git commit: $Format:%H$ */
  351. /* commit time: $Format:%ai$ */