int get_priv_key (unsigned char *ID, PRIVATE_KEY * privkey) { /* return key ID, or signature key if ID == NULL */ unsigned char line[1024], IDstr[80]; unsigned char newID[16]; int found = 0; FILE *privring; FILE *privlock; unsigned long t; if (ID != NULL) encode_ID (IDstr, ID); mix_lock ("secring", &privlock); if ((privring = open_mix_file (SECRING, "r")) == NULL) { mix_unlock ("secring", privlock); return (-1); } while (!found) { getline (line, sizeof (line), privring); while (!streq (line, begin_key)) { if (getline (line, sizeof (line), privring) == NULL) { fclose (privring); mix_unlock ("secring", privlock); goto notfound; } } getline (line, sizeof (line), privring); /* THIS SHOULD NOT RELY ON THE ORDER OF THE LINES ** */ if (strstr (line, KEY_VERSION)) getline (line, sizeof (line), privring); if (strstr (line, KEY_VALID)) { sscanf (line, KEY_VALID "%lu", &t); if ((unsigned long) time (NULL) < t) continue; /* don't use keys that aren't currently valid */ } if (strstr (line, KEY_EXPIRES)) { sscanf (line, KEY_EXPIRES "%lu", &t); if (t < (unsigned long) time (NULL)) continue; } if ((ID != NULL) && strstr (line, KEY_TYPE) && strstr (line, "sig")) continue; /* use sig key only if asked */ if ((ID != NULL && strstr (line, IDstr)) || ((ID == NULL) && strstr (line, KEY_TYPE) && strstr (line, "sig"))) { /* we use this key if the ID matches or it is the sig key we need */ if (strstr (line, "sig")) getline (line, sizeof (line), privring); /* read and drop ID */ if (read_priv_key (privring, privkey, newID) != 0) break; /* compare new ID with passed ID */ if ((ID != NULL) && (memcmp (ID, newID, 16) != 0)) { fprintf (errlog, "Error: Private Key IDs do not match! Bad passphrase?\n"); break; } found = 1; /* this will end the loop */ } } fclose (privring); mix_unlock ("secring", privlock); if (found) return (0); notfound: if (ID == NULL) fprintf (errlog, "Unable to get signature key!\n"); else fprintf (errlog, "Unable to get private key %s!\n", IDstr); return (1); }
void write_keyfile (void) { /* read the public keys from secring.mix... */ FILE *privring, *privlock; FILE *keyfile, *keylock, *keyinfo; BUFFER *b1, *buff, *header; #ifdef NEW BUFFER *signature; #endif char line[1024], IDstr[80]; long pos; int i, len; byte tmpbyte; PRIVATE_KEY privkey; unsigned char ID[16]; char abilities[256] = ""; #ifndef USE_RSAREF A_PKCS_RSA_PRIVATE_KEY *pkinfo; #endif our_abilities (abilities); mix_lock ("secring", &privlock); if ((privring = open_mix_file (SECRING, "r+")) == NULL) { mix_unlock ("secring", privlock); return; } buff = new_buffer (); #ifdef NEW str_to_buffer (buff, begin_signed); str_to_buffer (buff, "\n"); #endif while ((pos = next_key (privring)) != -1) { header = new_buffer (); for (;;) /* copy the header and to a buffer */ { getline (line, sizeof (line), privring); if (!strstr (line, ": ")) break; str_to_buffer (header, line); } if (read_priv_key (privring, &privkey, ID) != 0) break; encode_ID (IDstr, ID); if (memcmp (line, IDstr, 32) != 0) { fprintf (errlog, "Error: Private Key IDs do not match! Bad passphrase?\n"); fclose (privring); mix_unlock ("secring", privlock); exit (-1); } /* write key to buff */ if (header->length == 0) { /* old format */ sprintf (line, "%s %s ", SHORTNAME, REMAILERADDR); str_to_buffer (buff, line); str_to_buffer (buff, IDstr); str_to_buffer (buff, " "); str_to_buffer (buff, mixmaster_protocol); str_to_buffer (buff, VERSION); str_to_buffer (buff, " "); str_to_buffer (buff, abilities); str_to_buffer (buff, "\n\n"); str_to_buffer (buff, begin_key); str_to_buffer (buff, "\n"); } else { str_to_buffer (buff, begin_key); str_to_buffer (buff, "\n"); add_to_buffer (buff, header->message, header->length); } str_to_buffer (buff, IDstr); str_to_buffer (buff, "\n"); free_buffer (header); /* Armor pubkey */ b1 = new_buffer (); #ifdef USE_RSAREF /* Convert pubkey.bits to two bytes */ i = privkey.bits; #else B_GetKeyInfo ((POINTER *) & pkinfo, privkey, KI_PKCS_RSAPrivate); i = pkinfo->modulus.len * 8; #endif tmpbyte = i & 0xFF; add_to_buffer (b1, &tmpbyte, 1); /* low byte of bits */ i = i / 256; tmpbyte = i & 0xFF; add_to_buffer (b1, &tmpbyte, 1); /* high byte of bits */ #ifdef USE_RSAREF add_to_buffer (b1, privkey.modulus, MAX_RSA_MODULUS_LEN); add_to_buffer (b1, privkey.publicExponent, MAX_RSA_MODULUS_LEN); #else add_to_buffer (b1, pkinfo->modulus.data, pkinfo->modulus.len); if (pkinfo->publicExponent.len < pkinfo->modulus.len) add_to_buffer (b1, NULL, pkinfo->modulus.len - pkinfo->publicExponent.len); add_to_buffer (b1, pkinfo->publicExponent.data, pkinfo->publicExponent.len); #endif len = b1->length; while ((b1->length % 3) != 0) str_to_buffer (b1, "X"); sprintf (line, "%d\n", len); str_to_buffer (buff, line); armor (b1); add_to_buffer (buff, b1->message, b1->length); free_buffer (b1); str_to_buffer (buff, end_key); str_to_buffer (buff, "\n"); } fclose (privring); mix_unlock ("secring", privlock); #ifdef NEW str_to_buffer (buff, begin_cfg); sprintf (line, "\n%s%s\n", KEY_VERSION, VERSION); str_to_buffer (buff, line); sprintf (line, "%s%s\n", CFG_REMAILER, SHORTNAME); str_to_buffer (buff, line); sprintf (line, "%s%s\n", CFG_ADDRESS, REMAILERADDR); str_to_buffer (buff, line); sprintf (line, "%s%s\n", CFG_ABILITIES, abilities); str_to_buffer (buff, line); sprintf (line, "%s%lu\n", CFG_DATE, (unsigned long) time (NULL)); str_to_buffer (buff, line); str_to_buffer (buff, end_cfg); signature = new_buffer (); create_sig (buff, signature); armor (signature); str_to_buffer (buff, "\n"); str_to_buffer (buff, begin_signature); str_to_buffer (buff, "\n"); add_to_buffer (buff, signature->message, signature->length); str_to_buffer (buff, end_signature); #endif mix_lock ("key", &keylock); if ((keyinfo = open_mix_file (KEYINFO, "r")) == NULL || (keyfile = open_mix_file (KEYFILE, "w")) == NULL) { mix_unlock ("key", keylock); return; } while (getline (line, sizeof (line), keyinfo) != NULL) fprintf (keyfile, "%s\n", line); fclose (keyinfo); write_buffer (buff, keyfile); fclose (keyfile); mix_unlock ("key", keylock); free_buffer (buff); }
/* * RSA public decryption function. * Dencrypt 'in_len' bytes from 'envelope' buffer with the private key contained in 'priv_key_file' * Parameter 'outlen' is the size of output buffer * It returns the received plaintext or NULL if an error occurs. */ unsigned char* asym_decrypt(unsigned char* envelope, int in_len, int* out_len, char* priv_key_file){ EVP_PKEY* priv_key; int ret; EVP_CIPHER_CTX* ctx; unsigned char* encrypted_key; int encrypted_key_len; unsigned char* iv; int iv_len; unsigned char* ciphertext; int ciphertext_len; unsigned char* output; int output_len; int app; if(ciphertext == NULL || in_len < 0 || out_len == NULL || priv_key_file == NULL) return NULL; //Reads the receiver's public key for its file priv_key = read_priv_key(priv_key_file); //Note: envelope format -> <IV><Dim_Key><Ecrypt_KEY><Ciphertext> //Set to the head the iv pointer iv = envelope; iv_len = EVP_CIPHER_iv_length(SYM_CIPHER); //Read from the envelop the encrypted_key_len memcpy(&encrypted_key_len, envelope + iv_len, sizeof(int)); //Set the encrypted_key pointer encrypted_key = envelope + iv_len + sizeof(int); //Set the ciphertext pointer ciphertext = envelope + iv_len + sizeof(int) + encrypted_key_len; ciphertext_len = in_len - iv_len - sizeof(int) - encrypted_key_len; //Instantiate and initialize the context ctx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX)); EVP_CIPHER_CTX_init(ctx); ret = EVP_OpenInit(ctx, SYM_CIPHER, encrypted_key, encrypted_key_len, iv, priv_key); if(ret == 0) goto error; //Decrypt the ciphertext output_len = ciphertext_len; output = malloc(output_len); output_len = 0; ret = EVP_OpenUpdate(ctx, output, &app, ciphertext, ciphertext_len); if(ret == 0) goto error; output_len += app; ret = EVP_OpenFinal(ctx, output + app, &app); if(ret == 0) goto error; output_len += app; *out_len = output_len; //Cleanup EVP_CIPHER_CTX_cleanup(ctx); free(ctx); free(priv_key); return output; error: if(ctx != NULL){ EVP_CIPHER_CTX_cleanup(ctx); free(ctx); } if(encrypted_key != NULL) free(ciphertext); if(priv_key != NULL) free(priv_key); if(iv != NULL) free(iv); if(ciphertext != NULL) free(ciphertext); if(output != NULL) free(output); return NULL; }