aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/aescbc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/aescbc.c')
-rw-r--r--src/cmd/aescbc.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/cmd/aescbc.c b/src/cmd/aescbc.c
new file mode 100644
index 00000000..9f4bfff9
--- /dev/null
+++ b/src/cmd/aescbc.c
@@ -0,0 +1,144 @@
+/* encrypt file by writing
+ v2hdr,
+ 16byte initialization vector,
+ AES-CBC(key, random | file),
+ HMAC_SHA1(md5(key), AES-CBC(random | file))
+
+With CBC, if the first plaintext block is 0, the first ciphertext block is
+E(IV). Using the overflow technique adopted for compatibility with cryptolib
+makes the last cipertext block decryptable. Hence the random prefix to file.
+*/
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mp.h>
+#include <libsec.h>
+
+enum{ CHK = 16, BUF = 4096 };
+
+uchar v2hdr[AESbsize+1] = "AES CBC SHA1 2\n";
+Biobuf bin;
+Biobuf bout;
+
+void
+safewrite(uchar *buf, int n)
+{
+ int i = Bwrite(&bout, buf, n);
+
+ if(i == n)
+ return;
+ fprint(2, "write error\n");
+ exits("write error");
+}
+
+void
+saferead(uchar *buf, int n)
+{
+ int i = Bread(&bin, buf, n);
+
+ if(i == n)
+ return;
+ fprint(2, "read error\n");
+ exits("read error");
+}
+
+int
+main(int argc, char **argv)
+{
+ int encrypt = 0; /* 0=decrypt, 1=encrypt */
+ int n, nkey;
+ char *hex, *msg = nil;
+ uchar key[AESmaxkey], key2[MD5dlen];
+ uchar buf[BUF+SHA1dlen]; /* assumption: CHK <= SHA1dlen */
+ AESstate aes;
+ DigestState *dstate;
+
+ if(argc!=2 || argv[1][0]!='-'){
+ fprint(2,"usage: HEX=key %s -d < cipher.aes > clear.txt\n", argv[0]);
+ fprint(2," or: HEX=key %s -e < clear.txt > cipher.aes\n", argv[0]);
+ exits("usage");
+ }
+ if(argv[1][1] == 'e')
+ encrypt = 1;
+ Binit(&bin, 0, OREAD);
+ Binit(&bout, 1, OWRITE);
+
+ if((hex = getenv("HEX")) == nil)
+ hex = getpass("enter key: ");
+ nkey = 0;
+ if(hex != nil)
+ nkey = strlen(hex);
+ if(nkey == 0 || (nkey&1) || nkey>2*AESmaxkey){
+ fprint(2,"key should be 32 hex digits\n");
+ exits("key");
+ }
+ nkey = dec16(key, sizeof key, hex, nkey);
+ md5(key, nkey, key2, 0); /* so even if HMAC_SHA1 is broken, encryption key is protected */
+
+ if(encrypt){
+ safewrite(v2hdr, AESbsize);
+ genrandom(buf,2*AESbsize); /* CBC is semantically secure if IV is unpredictable. */
+ setupAESstate(&aes, key, nkey, buf); /* use first AESbsize bytes as IV */
+ aesCBCencrypt(buf+AESbsize, AESbsize, &aes); /* use second AESbsize bytes as initial plaintext */
+ safewrite(buf, 2*AESbsize);
+ dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
+ while(1){
+ n = Bread(&bin, buf, BUF);
+ if(n < 0){
+ msg = "read error";
+ goto Exit;
+ }
+ aesCBCencrypt(buf, n, &aes);
+ safewrite(buf, n);
+ dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
+ if(n < BUF)
+ break; /* EOF */
+ }
+ hmac_sha1(0, 0, key2, MD5dlen, buf, dstate);
+ safewrite(buf, SHA1dlen);
+ }else{ /* decrypt */
+ Bread(&bin, buf, AESbsize);
+ if(memcmp(buf, v2hdr, AESbsize) == 0){
+ saferead(buf, 2*AESbsize); /* read IV and random initial plaintext */
+ setupAESstate(&aes, key, nkey, buf);
+ dstate = hmac_sha1(buf+AESbsize, AESbsize, key2, MD5dlen, 0, 0);
+ aesCBCdecrypt(buf+AESbsize, AESbsize, &aes);
+ saferead(buf, SHA1dlen);
+ while((n = Bread(&bin, buf+SHA1dlen, BUF)) > 0){
+ dstate = hmac_sha1(buf, n, key2, MD5dlen, 0, dstate);
+ aesCBCdecrypt(buf, n, &aes);
+ safewrite(buf, n);
+ memmove(buf, buf+n, SHA1dlen); /* these bytes are not yet decrypted */
+ }
+ hmac_sha1(0, 0, key2, MD5dlen, buf+SHA1dlen, dstate);
+ if(memcmp(buf, buf+SHA1dlen, SHA1dlen) != 0){
+ msg = "decrypted file failed to authenticate!";
+ goto Exit;
+ }
+ }else{ /* compatibility with past mistake */
+ // if file was encrypted with bad aescbc use this:
+ // memset(key, 0, AESmaxkey);
+ // else assume we're decrypting secstore files
+ setupAESstate(&aes, key, 0, buf);
+ saferead(buf, CHK);
+ aesCBCdecrypt(buf, CHK, &aes);
+ while((n = Bread(&bin, buf+CHK, BUF)) > 0){
+ aesCBCdecrypt(buf+CHK, n, &aes);
+ safewrite(buf, n);
+ memmove(buf, buf+n, CHK);
+ }
+ if(memcmp(buf, "XXXXXXXXXXXXXXXX", CHK) != 0){
+ msg = "decrypted file failed to authenticate";
+ goto Exit;
+ }
+ }
+ }
+ Exit:
+ memset(key, 0, sizeof(key));
+ memset(key2, 0, sizeof(key2));
+ memset(buf, 0, sizeof(buf));
+ if(msg != nil)
+ fprint(2, "%s\n", msg);
+ exits(msg);
+ return 1; /* gcc */
+}