📄 roil.c
字号:
}introil_cipher(struct roil_pack *rp){ int n, m, mode; EVP_CIPHER_CTX ea_context; const EVP_CIPHER *ea; u_long bytecnt; u_char buf[BUF_SIZE], ebuf[BUF_SIZE], key[KEY_LENGTH], iv[IV_LENGTH]; /* set the mode for the cipher functions */ mode = (rp->flags & ENCRYPT) ? 1 : 0; /* add all available encryption algorithms to the hash table */ OpenSSL_add_all_ciphers(); if (rp->flags & ENCRYPT) { /* * If we're encrypting, we have to first load and verify the * cipher specified at the command line. */ ea = EVP_get_cipherbyname(rp->ea); if (ea == NULL) { snprintf(rp->errbuf, ERRBUF_SIZE, "unknown cipher %s\n", rp->ea); return (-1); } } else /* decrypting */ { /* * If we're decrypting, we have to check to see if this file was * previously encrypted by roil. To do that, we read the first 8 * bytes and see if they correspond to the "magic number" that is * written to every roiled file prior to encryption. */ n = read(rp->fd_in, buf, 8); if (n != 8) { snprintf(rp->errbuf, ERRBUF_SIZE, "read error %s\n", strerror(errno)); return (-1); } if (bcmp(buf, magic, 8)) { snprintf(rp->errbuf, ERRBUF_SIZE, "%s is not a roiled file\n", rp->fn_in); return (-1); } /* * Next, we have to determine which symmetric cipher was used * to encrypt the file. That is written in the next 16 bytes * of the file. */ n = read(rp->fd_in, buf, 16); if (n != 16) { snprintf(rp->errbuf, ERRBUF_SIZE, "read error %s\n", strerror(errno)); return (-1); } /* * Look up the cipher by canonical name and if it's "good" fill * in an EVP_CIPHER structure. */ ea = EVP_get_cipherbyname(buf); if (ea == NULL) { snprintf(rp->errbuf, ERRBUF_SIZE, "unknown cipher %s\n", buf); return (-1); } /* * The next 8 bytes contain the initialization vector, which * may or may not be used by the algorithm. We store it either * way. */ n = read(rp->fd_in, iv, 8); if (n != 8) { snprintf(rp->errbuf, ERRBUF_SIZE, "read error %s\n", strerror(errno)); return (-1); } } /* * Get a passphrase from the user to use as a key for the symmetric * encryption. */ if (get_passphrase(rp->passphrase) == -1) { snprintf(rp->errbuf, ERRBUF_SIZE, "can't read passphrase %s\n", strerror(errno)); return (-1); } /* * Take the passphrase and hash it using SHA1 to create our * symmetric key. */ if (make_key(rp, key) == -1) { /* error set in roil_digest() */ return (-1); } /* we appear good to go; we open our output file */ if (open_outputfile(rp) == -1) { /* error set in open_outputfile() */ return (-1); } if (rp->flags & ENCRYPT) { /* * Write out our 8 byte magic number to the file. This will * let the decryption code know if this file was encrypted by * us or not. */ n = write(rp->fd_out, magic, 8); if (n != 8) { snprintf(rp->errbuf, ERRBUF_SIZE, "write error %s\n", strerror(errno)); return (-1); } /* * Write the encryption algorithm to the file, which will be * NULL padded to 16 bytes. This will allow the decryption * code to figure it out without needing the user to specify. */ memset(buf, 0, sizeof (buf)); memcpy(buf, rp->ea, strlen(rp->ea)); n = write(rp->fd_out, buf, 16); if (n != 16) { snprintf(rp->errbuf, ERRBUF_SIZE, "write error %s\n", strerror(errno)); return (-1); } /* * Some encryption algorithms use an initialization vector to * seed the first round of encryption with (it acts as a dummy * block). We might need it so we'll get one and write it to * the file next. */ get_iv(iv); n = write(rp->fd_out, iv, 8); if (n != 8) { snprintf(rp->errbuf, ERRBUF_SIZE, "write error %s\n", strerror(errno)); return (-1); } } /* * Initialize the cipher context. Really all this does is zero * out the structure. */ EVP_CIPHER_CTX_init(&ea_context); /* initialize the encryption/decryption operation */ if (EVP_CipherInit_ex(&ea_context, ea, NULL, key, iv, mode) == 0) { snprintf(rp->errbuf, ERRBUF_SIZE, "EVP_CipherInit_ex() failed\n"); return (-1); } /* * Encrypt/decrypt the file. Read a block of data, encrypt it and * write it out to the file. */ if (rp->flags & ENCRYPT) { fprintf(stderr, "\nencrypting file \"%s\"\n", rp->fn_in); } else { fprintf(stderr, "\ndecrypting %s encrypted file \"%s\"\n", buf, rp->fn_in); } bytecnt = 0; while ((n = read(rp->fd_in, buf, sizeof (buf))) > 0) { bytecnt += n; /* * Encrypt or decrypt n bytes from buf and write the output to * ebuf. */ if (EVP_CipherUpdate(&ea_context, ebuf, &m, buf, n) == 0) { snprintf(rp->errbuf, ERRBUF_SIZE, "EVP_CipherUpdate() failed\n"); return (-1); } n = write(rp->fd_out, ebuf, m); if (n != m) { snprintf(rp->errbuf, ERRBUF_SIZE, "write error %s\n", strerror(errno)); return (-1); } fprintf(stderr, "byte: 0x%08lx\r", bytecnt); } /* * Finalize the encryption or decryption by taking care of padding * the last block if necessary. */ if (EVP_CipherFinal_ex(&ea_context, ebuf, &m) == 0) { snprintf(rp->errbuf, ERRBUF_SIZE, "EVP_CipherFinal_ex() failed\n"); return (-1); } n = write(rp->fd_out, ebuf, m); if (n != m) { snprintf(rp->errbuf, ERRBUF_SIZE, "write error %s\n", strerror(errno)); return (-1); } printf("\ndone, output file is \"%s\"\n", rp->fn_out); return (1);}intget_passphrase(char *passphrase){ int n, retry; char passphrase_match[KEY_LENGTH]; struct termios term; /* we want to turn off terminal echoing so no one can see! */ n = tcgetattr(STDIN_FILENO, &term); if (n == -1) { fprintf(stderr, "warning: password will be echoed\n"); /* nonfatal */ } else { /* disable terminal echo */ term.c_lflag &= ~ECHO; } /* set our changed state "NOW" */ n = tcsetattr(STDIN_FILENO, TCSANOW, &term); if (n == -1) { fprintf(stderr, "warning: password will be echoed\n"); /* nonfatal */ } retry = RETRY_THRESHOLD; memset(passphrase, 0, KEY_LENGTH);again: printf("Passphrase: "); if (fgets(passphrase, KEY_LENGTH, stdin) == NULL) { return (-1); } passphrase[strlen(passphrase) - 1] = 0; printf("\nAgain: "); if (fgets(passphrase_match, KEY_LENGTH, stdin) == NULL) { return (-1); } passphrase_match[strlen(passphrase_match) - 1] = 0; /* * Check to make sure they match. It's safe to use strcmp here * since we're confident both strings will be KEY_LENGTH or fewer * bytes. */ if (strcmp(passphrase, passphrase_match)) { if (retry <= 0) { /* we've run through this RETRY_THRESHOLD times, we're done */ fprintf(stderr, "\nyou're hopeless; get typing lessons\n"); errno = EPERM; /* this is as good as any I suppose */ return (-1); } fprintf(stderr, "\nno doofus, they don't match, try again\n"); retry--; goto again; } memset(passphrase_match, 0, KEY_LENGTH); return (1);}intmake_key(struct roil_pack *rp, u_char *key){ int len; u_char *p; strncpy(rp->md, "sha1", 4); p = roil_digest(rp, &len); if (p == NULL) { /* error set in roil_digest() */ return (-1); } memcpy(key, p, len); return (1);}voidget_iv(u_char *iv){ int n; /* XXX - should use the rand() interface from OpenSSL */ srandom((unsigned)time(NULL)); /* get 8 bytes of pseudo random value, from 0 - 255 */ for (n = 0; n < IV_LENGTH; n++) { iv[n] = random() % 0xff; }}voidusage(char *name){ printf("usage %s [options] file\n" "-e cipher_type\t\tencrypt\n" "-d\t\t\tdecrypt\n" "-h\t\t\tthis blurb you see right here\n" "-m message_digest\tmessage digest\n", name);}/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -