bool cipher::decrypt(string const &cipher,string &plain,time_t *timeout) { vector<unsigned char> data; base64_dec(cipher,data); size_t norm_size=b64url::decoded_size(cipher.size()); if(norm_size<sizeof(info)+sizeof(aes_hdr) || norm_size % 16 !=0) return false; gcry_cipher_decrypt(hd_in,&data.front(),data.size(),NULL,0); gcry_cipher_reset(hd_in); vector<char> md5(16,0); gcry_md_hash_buffer(GCRY_MD_MD5,&md5.front(),&data.front()+sizeof(aes_hdr),data.size()-sizeof(aes_hdr)); aes_hdr &aes_header = *(aes_hdr*)&data.front(); if(!std::equal(md5.begin(),md5.end(),aes_header.md5)) { return false; } info &header=*(info *)(&data.front()+sizeof(aes_hdr)); if(time(NULL)>header.timeout) return false; if(timeout) *timeout=header.timeout; vector<unsigned char>::iterator data_start=data.begin()+sizeof(aes_hdr)+sizeof(info), data_end=data_start+header.size; plain.assign(data_start,data_end); return true; }
void decryptFile(gcry_cipher_hd_t hd, char *filename) { FILE *encrypted_file; unsigned char encrypted_data[MAX_DATA_LEN], plain_data[MAX_DATA_LEN]; gcry_error_t err = 0; if ((encrypted_file = fopen(filename, "r")) == NULL) { fprintf(stderr, "Cannot open %s\n", filename); exit(1); } fread(encrypted_data, MAX_DATA_LEN, 1, encrypted_file); while (!feof(encrypted_file) && !ferror(encrypted_file)) { err = gcry_cipher_decrypt(hd, plain_data, MAX_DATA_LEN, encrypted_data, MAX_DATA_LEN); if (err) { printf("grcy_cipher_decrypt failed: %s\n", gpg_strerror(err)); exit(2); } gcry_cipher_reset(hd); printf("entrada: "); printCharArray(encrypted_data, MAX_DATA_LEN); printf("salida: "); printCharArray(plain_data, MAX_DATA_LEN); fread(encrypted_data, MAX_DATA_LEN, 1, encrypted_file); } fclose(encrypted_file); }
void SymmetricCipherGcrypt::reset() { gcry_error_t error; error = gcry_cipher_reset(m_ctx); Q_ASSERT(error == 0); error = gcry_cipher_setiv(m_ctx, m_iv.constData(), m_iv.size()); Q_ASSERT(error == 0); }
void encryptDecryptTest(gcry_cipher_hd_t hd, char *plain_filename) { FILE *plain_file; unsigned char encrypted_data[MAX_DATA_LEN], plain_data[MAX_DATA_LEN]; gcry_error_t err = 0; int blocks_to_read = 1; if ((plain_file = fopen(plain_filename, "r")) == NULL) { fprintf(stderr, "Cannot open %s\n", plain_filename); exit(1); } while (!feof(plain_file) && !ferror(plain_file)) { //memcpy(plain_data, " ", MAX_DATA_LEN); fillCharVectorWithSpaces(plain_data, MAX_DATA_LEN); fread(plain_data, MAX_DATA_LEN, blocks_to_read, plain_file); err = gcry_cipher_encrypt(hd, encrypted_data, MAX_DATA_LEN, plain_data, MAX_DATA_LEN); if (err) { printf("grcy_cipher_encrypt failed: %s\n", gpg_strerror(err)); exit(2); } gcry_cipher_reset(hd); printf("entrada: "); printCharArray(plain_data, MAX_DATA_LEN); printf("salida: "); printCharArray(encrypted_data, MAX_DATA_LEN); err = gcry_cipher_decrypt(hd, plain_data, MAX_DATA_LEN, encrypted_data, MAX_DATA_LEN); gcry_cipher_reset(hd); printf("entrada: "); printCharArray(encrypted_data, MAX_DATA_LEN); printf("salida: "); printCharArray(plain_data, MAX_DATA_LEN); } fclose(plain_file); }
/** * ntfs_desx_decrypt */ static void ntfs_desx_decrypt(ntfs_fek *fek, u8 *outbuf, const u8 *inbuf) { gcry_error_t err; ntfs_desx_ctx *ctx = &fek->desx_ctx; err = gcry_cipher_reset(fek->gcry_cipher_hd); if (err != GPG_ERR_NO_ERROR) ntfs_log_error("Failed to reset des cipher (error 0x%x).\n", err); *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening; err = gcry_cipher_encrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0); if (err != GPG_ERR_NO_ERROR) ntfs_log_error("Des decryption failed (error 0x%x).\n", err); *(u64*)outbuf ^= ctx->in_whitening; }
size_t _encrypt_char_buf(QSP_ARG_DECL const char *in_buf, size_t in_len, uint8_t *out_buf, size_t out_len) { gcry_error_t status; size_t padded_len, n_blocks; char *pad_buf; int bs; if( my_cipher_handle == NULL ) init_gcrypt_subsystem(); /* gcrypt doesn't seem to offer padding, so the input * must be an integral number of blocks... */ bs=encryption_block_size(); if( bs <= 0 ) return 0; // when lib not present? n_blocks = in_len/bs; if( (in_len % bs) != 0 ){ int i; n_blocks++; padded_len = n_blocks * bs; pad_buf = getbuf(padded_len); memcpy(pad_buf,in_buf,in_len); i=in_len; while(i<padded_len) pad_buf[i++] = 0; } else { pad_buf = (char *)in_buf; padded_len=in_len; } if( out_len < padded_len ){ warn("encrypt_char_buf: output buffer too small for pad!?"); return 0; } status = gcry_cipher_encrypt(my_cipher_handle, out_buf,out_len,pad_buf,padded_len); CHECK_STATUS(encrypt_char_buf,gcry_cipher_encrypt) // how do we know how many chars actually written? status = gcry_cipher_reset(my_cipher_handle); CHECK_STATUS(encrypt_char_buf,gcry_cipher_reset) // if we allocated a buffer, then free it. if( pad_buf != in_buf ) givbuf(pad_buf); return padded_len; }
int qcrypto_cipher_setiv(QCryptoCipher *cipher, const uint8_t *iv, size_t niv, Error **errp) { gcry_cipher_hd_t handle = cipher->opaque; gcry_error_t err; gcry_cipher_reset(handle); err = gcry_cipher_setiv(handle, iv, niv); if (err != 0) { error_setg(errp, "Cannot set IV: %s", gcry_strerror(err)); return -1; } return 0; }
void extract_random_key(const uint8_t *stretchkey, const uint8_t *fst, const uint8_t *snd, uint8_t *randkey) { gcry_error_t gerr; gcry_cipher_hd_t hd; gerr = gcry_cipher_open(&hd, GCRY_CIPHER_TWOFISH, GCRY_CIPHER_MODE_ECB, GCRY_CIPHER_SECURE); if (gerr != GPG_ERR_NO_ERROR) gcrypt_fatal(gerr); gerr = gcry_cipher_setkey(hd, stretchkey, 32); if (gerr != GPG_ERR_NO_ERROR) gcrypt_fatal(gerr); gcry_cipher_decrypt(hd, randkey, 16, fst, 16); gcry_cipher_reset(hd); gcry_cipher_decrypt(hd, randkey + 16, 16, snd, 16); gcry_cipher_close(hd); }
void encryptFileToFile(gcry_cipher_hd_t hd, const char *plain_filename, const char *encrypted_filename) { FILE *plain_file, *encrypted_file; unsigned char encrypted_data[MAX_DATA_LEN], plain_data[MAX_DATA_LEN]; gcry_error_t err = 0; size_t elements_written; int blocks_to_write = 1; if ((plain_file = fopen(plain_filename, "r")) == NULL) { fprintf(stderr, "Cannot open %s\n", plain_filename); exit(1); } if ((encrypted_file = fopen(encrypted_filename, "w+")) == NULL) { fprintf(stderr, "Cannot open %s\n", encrypted_filename); exit(1); } while (!feof(plain_file) && !ferror(plain_file)) { //memcpy(plain_data, " ", MAX_DATA_LEN); fillCharVectorWithSpaces(plain_data, MAX_DATA_LEN); fread(plain_data, MAX_DATA_LEN, 1, plain_file); err = gcry_cipher_encrypt(hd, encrypted_data, MAX_DATA_LEN, plain_data, MAX_DATA_LEN); if (err) { printf("grcy_cipher_encrypt failed: %s\n", gpg_strerror(err)); exit(2); } elements_written = fwrite(encrypted_data, MAX_DATA_LEN, blocks_to_write, encrypted_file); if (elements_written < blocks_to_write) { printf("Tried to write %d blocks but written %zu bytes\n", blocks_to_write, elements_written); exit(3); } gcry_cipher_reset(hd); } fflush(encrypted_file); fclose(encrypted_file); fclose(plain_file); }
/** * ntfs_fek_decrypt_sector */ static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) { gcry_error_t err; err = gcry_cipher_reset(fek->gcry_cipher_hd); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to reset cipher: %s\n", gcry_strerror(err)); return -1; } /* * Note: You may wonder why we are not calling gcry_cipher_setiv() here * instead of doing it by hand after the decryption. The answer is * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give * it a length of 16 for AES256 so it does not like it. */ if (fek->alg_id == CALG_DESX) { int k; for (k=0; k<512; k+=8) { ntfs_desx_decrypt(fek, &data[k], &data[k]); } } else err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err)); return -1; } /* Apply the IV. */ if (fek->alg_id == CALG_AES_256) { ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); } else { /* All other algos (Des, 3Des, DesX) use the same IV. */ ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); } return 512; }
size_t _decrypt_char_buf(QSP_ARG_DECL const uint8_t *in_buf, size_t in_len, char *out_buf, size_t out_len ) { gcry_error_t status; int bs; if( my_cipher_handle == NULL ) init_gcrypt_subsystem(); bs = encryption_block_size(); if( bs <= 0 ) return 0; // when lib not present? if( (in_len % bs) != 0 ){ sprintf(ERROR_STRING, "decrypt_char_buf: input size (%ld) is not an integral number of blocks (bs = %d)!?", (long)in_len,bs); warn(ERROR_STRING); return 0; } status = gcry_cipher_decrypt(my_cipher_handle, out_buf,out_len,in_buf,in_len); CHECK_STATUS(decrypt_char_buf,gcry_cipher_decrypt) // how do we know how many chars actually written? status = gcry_cipher_reset(my_cipher_handle); CHECK_STATUS(decrypt_char_buf,gcry_cipher_reset) // If we padded, there will be zeroes at the end of the // message - we might assume that they are invalid, // as we are generally encrypting C strings? while( out_len >= 1 && out_buf[out_len-1]==0 ) out_len --; return out_len; }
static void check (int algo, const void *kek, size_t keklen, const void *data, size_t datalen, const void *expected, size_t expectedlen) { gcry_error_t err; gcry_cipher_hd_t hd; unsigned char outbuf[32+8]; size_t outbuflen; err = gcry_cipher_open (&hd, algo, GCRY_CIPHER_MODE_AESWRAP, 0); if (err) { fail ("gcry_cipher_open failed: %s\n", gpg_strerror (err)); return; } err = gcry_cipher_setkey (hd, kek, keklen); if (err) { fail ("gcry_cipher_setkey failed: %s\n", gpg_strerror (err)); return; } outbuflen = datalen + 8; if (outbuflen > sizeof outbuf) err = gpg_error (GPG_ERR_INTERNAL); else err = gcry_cipher_encrypt (hd, outbuf, outbuflen, data, datalen); if (err) { fail ("gcry_cipher_encrypt failed: %s\n", gpg_strerror (err)); return; } if (outbuflen != expectedlen || memcmp (outbuf, expected, expectedlen)) { const unsigned char *s; int i; fail ("mismatch at encryption!\n"); fprintf (stderr, "computed: "); for (i = 0; i < outbuflen; i++) fprintf (stderr, "%02x ", outbuf[i]); fprintf (stderr, "\nexpected: "); for (s = expected, i = 0; i < expectedlen; s++, i++) fprintf (stderr, "%02x ", *s); putc ('\n', stderr); } outbuflen = expectedlen - 8; if (outbuflen > sizeof outbuf) err = gpg_error (GPG_ERR_INTERNAL); else err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen); if (err) { fail ("gcry_cipher_decrypt failed: %s\n", gpg_strerror (err)); return; } if (outbuflen != datalen || memcmp (outbuf, data, datalen)) { const unsigned char *s; int i; fail ("mismatch at decryption!\n"); fprintf (stderr, "computed: "); for (i = 0; i < outbuflen; i++) fprintf (stderr, "%02x ", outbuf[i]); fprintf (stderr, "\nexpected: "); for (s = data, i = 0; i < datalen; s++, i++) fprintf (stderr, "%02x ", *s); putc ('\n', stderr); } /* Now the last step again with a key reset. */ gcry_cipher_reset (hd); outbuflen = expectedlen - 8; if (outbuflen > sizeof outbuf) err = gpg_error (GPG_ERR_INTERNAL); else err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen); if (err) { fail ("gcry_cipher_decrypt(2) failed: %s\n", gpg_strerror (err)); return; } if (outbuflen != datalen || memcmp (outbuf, data, datalen)) fail ("mismatch at decryption(2)!\n"); /* And once ore without a key reset. */ outbuflen = expectedlen - 8; if (outbuflen > sizeof outbuf) err = gpg_error (GPG_ERR_INTERNAL); else err = gcry_cipher_decrypt (hd, outbuf, outbuflen, expected, expectedlen); if (err) { fail ("gcry_cipher_decrypt(3) failed: %s\n", gpg_strerror (err)); return; } if (outbuflen != datalen || memcmp (outbuf, data, datalen)) fail ("mismatch at decryption(3)!\n"); gcry_cipher_close (hd); }
static int mode_encrypt(File filein, File fileout) { size_t bytesread; size_t chunkbuflen; void *chunkbuf = NULL; void *ivbuf = NULL; size_t encryptbuflen = 0; size_t encryptedlen = 0; void *encryptbuf = NULL; ulonglong ttlchunkswritten = 0; ulonglong ttlbyteswritten = 0; xb_wcrypt_t *xbcrypt_file = NULL; gcry_cipher_hd_t cipher_handle; gcry_error_t gcry_error; if (encrypt_algo != GCRY_CIPHER_NONE) { gcry_error = gcry_cipher_open(&cipher_handle, encrypt_algo, encrypt_mode, 0); if (gcry_error) { msg("%s:encrypt: unable to open libgcrypt cipher - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); return 1; } gcry_error = gcry_cipher_setkey(cipher_handle, opt_encrypt_key, encrypt_key_len); if (gcry_error) { msg("%s:encrypt: unable to set libgcrypt cipher key - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); goto err; } } posix_fadvise(filein, 0, 0, POSIX_FADV_SEQUENTIAL); xbcrypt_file = xb_crypt_write_open(&fileout, my_xb_crypt_write_callback); if (xbcrypt_file == NULL) { msg("%s:encrypt: xb_crypt_write_open() failed.\n", my_progname); goto err; } ivbuf = my_malloc(encrypt_iv_len, MYF(MY_FAE)); /* now read in data in chunk size, encrypt and write out */ chunkbuflen = opt_encrypt_chunk_size; chunkbuf = my_malloc(chunkbuflen, MYF(MY_FAE)); while ((bytesread = my_read(filein, chunkbuf, chunkbuflen, MYF(MY_WME))) > 0) { if (encrypt_algo != GCRY_CIPHER_NONE) { gcry_error = gcry_cipher_reset(cipher_handle); if (gcry_error) { msg("%s:encrypt: unable to reset cipher - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); goto err; } xb_crypt_create_iv(ivbuf, encrypt_iv_len); gcry_error = gcry_cipher_setiv(cipher_handle, ivbuf, encrypt_iv_len); if (gcry_error) { msg("%s:encrypt: unable to set cipher iv - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); continue; } if (encryptbuflen < bytesread) { if (encryptbuflen) { encryptbuf = my_realloc(encryptbuf, bytesread, MYF(MY_WME)); encryptbuflen = bytesread; } else { encryptbuf = my_malloc(bytesread, MYF(MY_WME)); encryptbuflen = bytesread; } } gcry_error = gcry_cipher_encrypt(cipher_handle, encryptbuf, encryptbuflen, chunkbuf, bytesread); encryptedlen = bytesread; if (gcry_error) { msg("%s:encrypt: unable to encrypt chunk - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); gcry_cipher_close(cipher_handle); goto err; } } else { encryptedlen = bytesread; encryptbuf = chunkbuf; } if (xb_crypt_write_chunk(xbcrypt_file, encryptbuf, bytesread, encryptedlen, ivbuf, encrypt_iv_len)) { msg("%s:encrypt: abcrypt_write_chunk() failed.\n", my_progname); goto err; } ttlchunkswritten++; ttlbyteswritten += encryptedlen; if (opt_verbose) msg("%s:encrypt: %llu chunks written, %llu bytes " "written\n.", my_progname, ttlchunkswritten, ttlbyteswritten); } my_free(ivbuf); my_free(chunkbuf); if (encryptbuf && encryptbuflen) my_free(encryptbuf); xb_crypt_write_close(xbcrypt_file); if (encrypt_algo != GCRY_CIPHER_NONE) gcry_cipher_close(cipher_handle); if (opt_verbose) msg("\n%s:encrypt: done\n", my_progname); return 0; err: if (chunkbuf) my_free(chunkbuf); if (encryptbuf && encryptbuflen) my_free(encryptbuf); if (xbcrypt_file) xb_crypt_write_close(xbcrypt_file); if (encrypt_algo != GCRY_CIPHER_NONE) gcry_cipher_close(cipher_handle); return 1; }
static void check_one_cipher (int algo, int mode, int flags) { gcry_cipher_hd_t hd; char key[32], plain[16], in[16], out[16]; int keylen; gcry_error_t err = 0; memcpy (key, "0123456789abcdef.,;/[]{}-=ABCDEF", 32); memcpy (plain, "foobar42FOOBAR17", 16); keylen = gcry_cipher_get_algo_keylen (algo); if (!keylen) { fail ("algo %d, mode %d, gcry_cipher_get_algo_keylen failed\n", algo, mode); return; } if (keylen < 40 / 8 || keylen > 32) { fail ("algo %d, mode %d, keylength problem (%d)\n", algo, mode, keylen); return; } err = gcry_cipher_open (&hd, algo, mode, flags); if (err) { fail ("algo %d, mode %d, grcy_open_cipher failed: %s\n", algo, mode, gpg_strerror (err)); return; } err = gcry_cipher_setkey (hd, key, keylen); if (err) { fail ("algo %d, mode %d, gcry_cipher_setkey failed: %s\n", algo, mode, gpg_strerror (err)); gcry_cipher_close (hd); return; } err = gcry_cipher_encrypt (hd, out, 16, plain, 16); if (err) { fail ("algo %d, mode %d, gcry_cipher_encrypt failed: %s\n", algo, mode, gpg_strerror (err)); gcry_cipher_close (hd); return; } gcry_cipher_reset (hd); err = gcry_cipher_decrypt (hd, in, 16, out, 16); if (err) { fail ("algo %d, mode %d, gcry_cipher_decrypt failed: %s\n", algo, mode, gpg_strerror (err)); gcry_cipher_close (hd); return; } gcry_cipher_close (hd); if (memcmp (plain, in, 16)) fail ("algo %d, mode %d, encrypt-decrypt mismatch\n", algo, mode); }
/* Create an OTR Data message. Pass the plaintext as msg, and an * optional chain of TLVs. A newly-allocated string will be returned in * *encmessagep. */ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context, const char *msg, const OtrlTLV *tlvs, unsigned char flags) { size_t justmsglen = strlen(msg); size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs); size_t buflen; size_t pubkeylen; unsigned char *buf = NULL; unsigned char *bufp; size_t lenp; DH_sesskeys *sess = &(context->sesskeys[1][0]); gcry_error_t err; size_t reveallen = 20 * context->numsavedkeys; size_t base64len; char *base64buf = NULL; unsigned char *msgbuf = NULL; enum gcry_mpi_format format = GCRYMPI_FMT_USG; char *msgdup; int version = context->protocol_version; /* Make sure we're actually supposed to be able to encrypt */ if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED || context->their_keyid == 0) { return gcry_error(GPG_ERR_CONFLICT); } /* We need to copy the incoming msg, since it might be an alias for * context->lastmessage, which we'll be freeing soon. */ msgdup = gcry_malloc_secure(justmsglen + 1); if (msgdup == NULL) { return gcry_error(GPG_ERR_ENOMEM); } strcpy(msgdup, msg); *encmessagep = NULL; /* Header, send keyid, recv keyid, counter, msg len, msg * len of revealed mac keys, revealed mac keys, MAC */ buflen = 3 + (version == 2 ? 1 : 0) + 4 + 4 + 8 + 4 + msglen + 4 + reveallen + 20; gcry_mpi_print(format, NULL, 0, &pubkeylen, context->our_dh_key.pub); buflen += pubkeylen + 4; buf = malloc(buflen); msgbuf = gcry_malloc_secure(msglen); if (buf == NULL || msgbuf == NULL) { free(buf); gcry_free(msgbuf); gcry_free(msgdup); return gcry_error(GPG_ERR_ENOMEM); } memmove(msgbuf, msgdup, justmsglen); msgbuf[justmsglen] = '\0'; otrl_tlv_serialize(msgbuf + justmsglen + 1, tlvs); bufp = buf; lenp = buflen; if (version == 1) { memmove(bufp, "\x00\x01\x03", 3); /* header */ } else { memmove(bufp, "\x00\x02\x03", 3); /* header */ } debug_data("Header", bufp, 3); bufp += 3; lenp -= 3; if (version == 2) { bufp[0] = flags; bufp += 1; lenp -= 1; } write_int(context->our_keyid-1); /* sender keyid */ debug_int("Sender keyid", bufp-4); write_int(context->their_keyid); /* recipient keyid */ debug_int("Recipient keyid", bufp-4); write_mpi(context->our_dh_key.pub, pubkeylen, "Y"); /* Y */ otrl_dh_incctr(sess->sendctr); memmove(bufp, sess->sendctr, 8); /* Counter (top 8 bytes only) */ debug_data("Counter", bufp, 8); bufp += 8; lenp -= 8; write_int(msglen); /* length of encrypted data */ debug_int("Msg len", bufp-4); err = gcry_cipher_reset(sess->sendenc); if (err) goto err; err = gcry_cipher_setctr(sess->sendenc, sess->sendctr, 16); if (err) goto err; err = gcry_cipher_encrypt(sess->sendenc, bufp, msglen, msgbuf, msglen); if (err) goto err; /* encrypted data */ debug_data("Enc data", bufp, msglen); bufp += msglen; lenp -= msglen; gcry_md_reset(sess->sendmac); gcry_md_write(sess->sendmac, buf, bufp-buf); memmove(bufp, gcry_md_read(sess->sendmac, GCRY_MD_SHA1), 20); debug_data("MAC", bufp, 20); bufp += 20; /* MAC */ lenp -= 20; write_int(reveallen); /* length of revealed MAC keys */ debug_int("Revealed MAC length", bufp-4); if (reveallen > 0) { memmove(bufp, context->saved_mac_keys, reveallen); debug_data("Revealed MAC data", bufp, reveallen); bufp += reveallen; lenp -= reveallen; free(context->saved_mac_keys); context->saved_mac_keys = NULL; context->numsavedkeys = 0; } assert(lenp == 0); /* Make the base64-encoding. */ base64len = ((buflen + 2) / 3) * 4; base64buf = malloc(5 + base64len + 1 + 1); if (base64buf == NULL) { err = gcry_error(GPG_ERR_ENOMEM); goto err; } memmove(base64buf, "?OTR:", 5); otrl_base64_encode(base64buf+5, buf, buflen); base64buf[5 + base64len] = '.'; base64buf[5 + base64len + 1] = '\0'; free(buf); gcry_free(msgbuf); *encmessagep = base64buf; gcry_free(context->lastmessage); context->lastmessage = NULL; context->may_retransmit = 0; if (msglen > 0) { const char *prefix = "[resent] "; size_t prefixlen = strlen(prefix); if (!strncmp(prefix, msgdup, prefixlen)) { /* The prefix is already there. Don't add it again. */ prefix = ""; prefixlen = 0; } context->lastmessage = gcry_malloc_secure(prefixlen + justmsglen + 1); if (context->lastmessage) { strcpy(context->lastmessage, prefix); strcat(context->lastmessage, msgdup); } } gcry_free(msgdup); return gcry_error(GPG_ERR_NO_ERROR); err: free(buf); gcry_free(msgbuf); gcry_free(msgdup); *encmessagep = NULL; return err; }
/* Accept an OTR Data Message in datamsg. Decrypt it and put the * plaintext into *plaintextp, and any TLVs into tlvsp. Put any * received flags into *flagsp (if non-NULL). */ gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp, ConnContext *context, const char *datamsg, unsigned char *flagsp) { char *otrtag, *endtag; gcry_error_t err; unsigned char *rawmsg = NULL; size_t msglen, rawlen, lenp; unsigned char *macstart, *macend; unsigned char *bufp; unsigned int sender_keyid, recipient_keyid; gcry_mpi_t sender_next_y = NULL; unsigned char ctr[8]; unsigned int datalen, reveallen; unsigned char *data = NULL; unsigned char *nul = NULL; unsigned char givenmac[20]; DH_sesskeys *sess; unsigned char version; *plaintextp = NULL; *tlvsp = NULL; if (flagsp) *flagsp = 0; otrtag = strstr(datamsg, "?OTR:"); if (!otrtag) { goto invval; } endtag = strchr(otrtag, '.'); if (endtag) { msglen = endtag-otrtag; } else { msglen = strlen(otrtag); } /* Base64-decode the message */ rawlen = ((msglen-5) / 4) * 3; /* maximum possible */ rawmsg = malloc(rawlen); if (!rawmsg && rawlen > 0) { err = gcry_error(GPG_ERR_ENOMEM); goto err; } rawlen = otrl_base64_decode(rawmsg, otrtag+5, msglen-5); /* actual size */ bufp = rawmsg; lenp = rawlen; macstart = bufp; require_len(3); if (memcmp(bufp, "\x00\x01\x03", 3) && memcmp(bufp, "\x00\x02\x03", 3)) { /* Invalid header */ goto invval; } version = bufp[1]; bufp += 3; lenp -= 3; if (version == 2) { require_len(1); if (flagsp) *flagsp = bufp[0]; bufp += 1; lenp -= 1; } read_int(sender_keyid); read_int(recipient_keyid); read_mpi(sender_next_y); require_len(8); memmove(ctr, bufp, 8); bufp += 8; lenp -= 8; read_int(datalen); require_len(datalen); data = malloc(datalen+1); if (!data) { err = gcry_error(GPG_ERR_ENOMEM); goto err; } memmove(data, bufp, datalen); data[datalen] = '\0'; bufp += datalen; lenp -= datalen; macend = bufp; require_len(20); memmove(givenmac, bufp, 20); bufp += 20; lenp -= 20; read_int(reveallen); require_len(reveallen); /* Just skip over the revealed MAC keys, which we don't need. They * were published for deniability of transcripts. */ bufp += reveallen; lenp -= reveallen; /* That should be everything */ if (lenp != 0) goto invval; /* We don't take any action on this message (especially rotating * keys) until we've verified the MAC on this message. To that end, * we need to know which keys this message is claiming to use. */ if (context->their_keyid == 0 || (sender_keyid != context->their_keyid && sender_keyid != context->their_keyid - 1) || (recipient_keyid != context->our_keyid && recipient_keyid != context->our_keyid - 1) || sender_keyid == 0 || recipient_keyid == 0) { goto conflict; } if (sender_keyid == context->their_keyid - 1 && context->their_old_y == NULL) { goto conflict; } /* These are the session keys this message is claiming to use. */ sess = &(context->sesskeys [context->our_keyid - recipient_keyid] [context->their_keyid - sender_keyid]); gcry_md_reset(sess->rcvmac); gcry_md_write(sess->rcvmac, macstart, macend-macstart); if (memcmp(givenmac, gcry_md_read(sess->rcvmac, GCRY_MD_SHA1), 20)) { /* The MACs didn't match! */ goto conflict; } sess->rcvmacused = 1; /* Check to see that the counter is increasing; i.e. that this isn't * a replay. */ if (otrl_dh_cmpctr(ctr, sess->rcvctr) <= 0) { goto conflict; } /* Decrypt the message */ memmove(sess->rcvctr, ctr, 8); err = gcry_cipher_reset(sess->rcvenc); if (err) goto err; err = gcry_cipher_setctr(sess->rcvenc, sess->rcvctr, 16); if (err) goto err; err = gcry_cipher_decrypt(sess->rcvenc, data, datalen, NULL, 0); if (err) goto err; /* See if either set of keys needs rotating */ if (recipient_keyid == context->our_keyid) { /* They're using our most recent key, so generate a new one */ err = rotate_dh_keys(context); if (err) goto err; } if (sender_keyid == context->their_keyid) { /* They've sent us a new public key */ err = rotate_y_keys(context, sender_next_y); if (err) goto err; } gcry_mpi_release(sender_next_y); *plaintextp = (char *)data; /* See if there are TLVs */ nul = data; while (nul < data+datalen && *nul) ++nul; /* If we stopped before the end, skip the NUL we stopped at */ if (nul < data+datalen) ++nul; *tlvsp = otrl_tlv_parse(nul, (data+datalen)-nul); free(rawmsg); return gcry_error(GPG_ERR_NO_ERROR); invval: err = gcry_error(GPG_ERR_INV_VALUE); goto err; conflict: err = gcry_error(GPG_ERR_CONFLICT); goto err; err: gcry_mpi_release(sender_next_y); free(data); free(rawmsg); return err; }
static int mode_decrypt(File filein, File fileout) { xb_rcrypt_t *xbcrypt_file = NULL; void *chunkbuf = NULL; size_t chunksize; size_t originalsize; void *ivbuf = NULL; size_t ivsize; void *decryptbuf = NULL; size_t decryptbufsize = 0; ulonglong ttlchunksread = 0; ulonglong ttlbytesread = 0; xb_rcrypt_result_t result; gcry_cipher_hd_t cipher_handle; gcry_error_t gcry_error; if (encrypt_algo != GCRY_CIPHER_NONE) { gcry_error = gcry_cipher_open(&cipher_handle, encrypt_algo, encrypt_mode, 0); if (gcry_error) { msg("%s:decrypt: unable to open libgcrypt" " cipher - %s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); return 1; } gcry_error = gcry_cipher_setkey(cipher_handle, opt_encrypt_key, encrypt_key_len); if (gcry_error) { msg("%s:decrypt: unable to set libgcrypt cipher" "key - %s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); goto err; } } /* Initialize the xb_crypt format reader */ xbcrypt_file = xb_crypt_read_open(&filein, my_xb_crypt_read_callback); if (xbcrypt_file == NULL) { msg("%s:decrypt: xb_crypt_read_open() failed.\n", my_progname); goto err; } /* Walk the encrypted chunks, decrypting them and writing out */ while ((result = xb_crypt_read_chunk(xbcrypt_file, &chunkbuf, &originalsize, &chunksize, &ivbuf, &ivsize)) == XB_CRYPT_READ_CHUNK) { if (encrypt_algo != GCRY_CIPHER_NONE) { gcry_error = gcry_cipher_reset(cipher_handle); if (gcry_error) { msg("%s:decrypt: unable to reset libgcrypt" " cipher - %s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); goto err; } if (ivsize) { gcry_error = gcry_cipher_setiv(cipher_handle, ivbuf, ivsize); } else { gcry_error = gcry_cipher_setiv(cipher_handle, v1_encrypt_iv, encrypt_iv_len); } if (gcry_error) { msg("%s:decrypt: unable to set cipher iv - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); continue; } if (decryptbufsize < originalsize) { if (decryptbufsize) { decryptbuf = my_realloc(decryptbuf, originalsize, MYF(MY_WME)); decryptbufsize = originalsize; } else { decryptbuf = my_malloc(originalsize, MYF(MY_WME)); decryptbufsize = originalsize; } } /* Try to decrypt it */ gcry_error = gcry_cipher_decrypt(cipher_handle, decryptbuf, originalsize, chunkbuf, chunksize); if (gcry_error) { msg("%s:decrypt: unable to decrypt chunk - " "%s : %s\n", my_progname, gcry_strsource(gcry_error), gcry_strerror(gcry_error)); gcry_cipher_close(cipher_handle); goto err; } } else { decryptbuf = chunkbuf; } /* Write it out */ if (my_write(fileout, decryptbuf, originalsize, MYF(MY_WME | MY_NABP))) { msg("%s:decrypt: unable to write output chunk.\n", my_progname); goto err; } ttlchunksread++; ttlbytesread += chunksize; if (opt_verbose) msg("%s:decrypt: %llu chunks read, %llu bytes read\n.", my_progname, ttlchunksread, ttlbytesread); } xb_crypt_read_close(xbcrypt_file); if (encrypt_algo != GCRY_CIPHER_NONE) gcry_cipher_close(cipher_handle); if (decryptbuf && decryptbufsize) my_free(decryptbuf); if (opt_verbose) msg("\n%s:decrypt: done\n", my_progname); return 0; err: if (xbcrypt_file) xb_crypt_read_close(xbcrypt_file); if (encrypt_algo != GCRY_CIPHER_NONE) gcry_cipher_close(cipher_handle); if (decryptbuf && decryptbufsize) my_free(decryptbuf); return 1; }