aescbc.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* encrypt file by writing
  2. v2hdr,
  3. 16byte initialization vector,
  4. AES-CBC(key, random | file),
  5. HMAC_SHA1(md5(key), AES-CBC(random | file))
  6. */
  7. #include <u.h>
  8. #include <libc.h>
  9. #include <bio.h>
  10. #include <mp.h>
  11. #include <libsec.h>
  12. #include <authsrv.h>
  13. extern char* getpassm(char*);
  14. enum{ CHK = 16, BUF = 4096 };
  15. uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
  16. Biobuf bin;
  17. Biobuf bout;
  18. void
  19. safewrite(uchar *buf, int n)
  20. {
  21. int i = Bwrite(&bout, buf, n);
  22. if(i == n)
  23. return;
  24. fprint(2, "write error\n");
  25. exits("write error");
  26. }
  27. void
  28. saferead(uchar *buf, int n)
  29. {
  30. int i = Bread(&bin, buf, n);
  31. if(i == n)
  32. return;
  33. fprint(2, "read error\n");
  34. exits("read error");
  35. }
  36. int
  37. main(int argc, char **argv)
  38. {
  39. int encrypt = 0; /* 0=decrypt, 1=encrypt */
  40. int n, nkey, pass_stdin = 0, pass_nvram = 0;
  41. char *pass;
  42. uchar key[AESmaxkey], key2[SHA1dlen];
  43. uchar buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */
  44. AESstate aes;
  45. DigestState *dstate;
  46. Nvrsafe nvr;
  47. ARGBEGIN{
  48. case 'e':
  49. encrypt = 1;
  50. break;
  51. case 'i':
  52. pass_stdin = 1;
  53. break;
  54. case 'n':
  55. pass_nvram = 1;
  56. break;
  57. }ARGEND;
  58. if(argc!=0){
  59. fprint(2,"usage: %s -d < cipher.aes > clear.txt\n", argv0);
  60. fprint(2," or: %s -e < clear.txt > cipher.aes\n", argv0);
  61. exits("usage");
  62. }
  63. Binit(&bin, 0, OREAD);
  64. Binit(&bout, 1, OWRITE);
  65. if(pass_stdin){
  66. n = readn(3, buf, (sizeof buf)-1);
  67. if(n < 1)
  68. exits("usage: echo password |[3=1] auth/aescbc -i ...");
  69. buf[n] = 0;
  70. while(buf[n-1] == '\n')
  71. buf[--n] = 0;
  72. }else if(pass_nvram){
  73. if(readnvram(&nvr, 0) < 0)
  74. exits("readnvram: %r");
  75. strecpy((char*)buf, (char*)buf+sizeof buf, (char*)nvr.config);
  76. n = strlen((char*)buf);
  77. }else{
  78. pass = getpassm("aescbc key:");
  79. n = strlen(pass);
  80. if(n >= BUF)
  81. exits("key too long");
  82. strcpy((char*)buf, pass);
  83. memset(pass, 0, n);
  84. free(pass);
  85. }
  86. if(n <= 0){
  87. fprint(2,"no key\n");
  88. exits("key");
  89. }
  90. dstate = sha1((uchar*)"aescbc file", 11, nil, nil);
  91. sha1(buf, n, key2, dstate);
  92. memcpy(key, key2, 16);
  93. nkey = 16;
  94. md5(key, nkey, key2, 0); /* so even if HMAC_SHA1 is broken, encryption key is protected */
  95. if(encrypt){
  96. safewrite(v2hdr, AESbsize);
  97. genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */
  98. setupAESstate(&aes, key, nkey, buf); /* use first AESbsize bytes as IV */
  99. aesCBCencrypt(buf+AESbsize, AESbsize, &aes); /* use second AESbsize bytes as initial plaintext */
  100. safewrite(buf, 2*AESbsize);
  101. dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
  102. while(1){
  103. n = Bread(&bin, buf, BUF);
  104. if(n < 0){
  105. fprint(2,"read error\n");
  106. exits("read error");
  107. }
  108. aesCBCencrypt(buf, n, &aes);
  109. safewrite(buf, n);
  110. dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
  111. if(n < BUF)
  112. break; /* EOF */
  113. }
  114. hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
  115. safewrite(buf, SHA1dlen);
  116. }else{ /* decrypt */
  117. saferead(buf, AESbsize);
  118. if(memcmp(buf, v2hdr, AESbsize) == 0){
  119. saferead(buf, 2*AESbsize); /* read IV and random initial plaintext */
  120. setupAESstate(&aes, key, nkey, buf);
  121. dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
  122. aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
  123. saferead(buf, SHA1dlen);
  124. while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
  125. dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
  126. aesCBCdecrypt(buf, n, &aes);
  127. safewrite(buf, n);
  128. memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */
  129. }
  130. hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
  131. if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0){
  132. fprint(2,"decrypted file failed to authenticate\n");
  133. exits("decrypted file failed to authenticate");
  134. }
  135. }else{ /* compatibility with past mistake */
  136. // if file was encrypted with bad aescbc use this:
  137. // memset(key, 0, AESmaxkey);
  138. // else assume we're decrypting secstore files
  139. setupAESstate(&aes, key, AESbsize, buf);
  140. saferead(buf, CHK);
  141. aesCBCdecrypt(buf, CHK, &aes);
  142. while((n = Bread(&bin, buf+CHK, BUF)) > 0){
  143. aesCBCdecrypt(buf+CHK, n, &aes);
  144. safewrite(buf, n);
  145. memmove(buf, buf+n, CHK);
  146. }
  147. if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0){
  148. fprint(2,"decrypted file failed to authenticate\n");
  149. exits("decrypted file failed to authenticate");
  150. }
  151. }
  152. }
  153. exits("");
  154. return 1; /* keep other compilers happy */
  155. }