+Sat Nov 2 21:26:56 EET 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added support for encrypted private key files. Now
+ passphrase must be provided when new key pair is created
+ (can be empty though), and prompted when loading the
+ private key. Added support for loading the old-style
+ non-encrypted private keys as well. Affected files
+ lib/silccrypt/silcpkcs.[ch], Irssi SILC client and
+ SILC Server.
+
+ * Fixed silc_get_input to accept input on all terminals.
+ Affected file lib/silcutil/silcutil.c.
+
+ * Moved the Irssi SILC client key loading and other stuff
+ to be called after the arguments and UI is initialized.
+ Affected file irssi/src/silc/core/silc-core.c. Bug #31.
+
Sat Nov 2 12:53:09 EET 2002 Pekka Riikonen <priikone@silcnet.org>
* Fixed connection closing in client library to not crash.
TODO/bugs In SILC Libraries
===========================
- o Private key encryption to silc_pkcs_[save/load]_private_key[_data]
- function.
-
o WIN32 silc_net_create_connection_async does not work the same way
than on Unix. Do it with threads on WIN32. The function works but
is not actually async currently (Fix this to 0.9.x).
silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
SILC_CLIENT_DEF_PKCS_LEN,
file_public_key, file_private_key, NULL,
- NULL, NULL, NULL, FALSE);
+ NULL, NULL, NULL, NULL, FALSE);
printf("Press <Enter> to continue...\n");
getchar();
} else {
silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
SILC_CLIENT_DEF_PKCS_LEN,
file_public_key, file_private_key, NULL,
- NULL, NULL, NULL, FALSE);
+ NULL, NULL, NULL, NULL, FALSE);
printf("Press <Enter> to continue...\n");
getchar();
} else {
silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
SILC_CLIENT_DEF_PKCS_LEN,
file_public_key, file_private_key, NULL,
- NULL, NULL, NULL, FALSE);
+ NULL, NULL, NULL, NULL, FALSE);
printf("Press <Enter> to continue...\n");
getchar();
} else {
{
char pub[256], prv[256];
struct passwd *pw;
+ bool ret;
SILC_LOG_DEBUG(("Loading public and private keys"));
snprintf(pub, sizeof(pub) - 1, "%s/%s",
get_irssi_dir(), SILC_CLIENT_PUBLIC_KEY_NAME);
- return silc_load_key_pair(pub, prv, &client->pkcs, &client->public_key,
- &client->private_key);
+ /* Try loading first with "" passphrase, for those that didn't set
+ passphrase for private key, and only if that fails let it prompt
+ for passphrase. */
+ ret = silc_load_key_pair(pub, prv, "", &client->pkcs, &client->public_key,
+ &client->private_key);
+ if (!ret)
+ ret = silc_load_key_pair(pub, prv, NULL, &client->pkcs,
+ &client->public_key, &client->private_key);
+ return ret;
}
silc_hash_register_default();
silc_hmac_register_default();
silc_create_key_pair(opt_pkcs, opt_bits, NULL, NULL, NULL,
- NULL, NULL, NULL, TRUE);
+ NULL, NULL, NULL, NULL, TRUE);
exit(0);
}
}
+static void sig_init_finished(void)
+{
+ /* Check ~/.silc directory and public and private keys */
+ if (!silc_client_check_silc_dir()) {
+ idletag = -1;
+ exit(1);
+ }
+
+ /* Load public and private key */
+ if (!silc_client_load_keys(silc_client)) {
+ idletag = -1;
+ exit(1);
+ }
+
+ /* Initialize the SILC client */
+ if (!silc_client_init(silc_client)) {
+ idletag = -1;
+ exit(1);
+ }
+}
+
/* Init SILC. Called from src/fe-text/silc.c */
void silc_core_init(void)
#endif
signal_add("setup changed", (SIGNAL_FUNC) sig_setup_changed);
+ signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
silc_init_userinfo();
silc_client->hostname = silc_net_localhost();
silc_client->realname = g_strdup(settings_get_str("real_name"));
- /* Check ~/.silc directory and public and private keys */
- if (silc_client_check_silc_dir() == FALSE) {
- idletag = -1;
- return;
- }
-
- /* Load public and private key */
- if (silc_client_load_keys(silc_client) == FALSE) {
- idletag = -1;
- return;
- }
-
- /* Initialize the SILC client */
- if (!silc_client_init(silc_client)) {
- idletag = -1;
- return;
- }
-
silc_log_set_callback(SILC_LOG_INFO, silc_log_misc, NULL);
silc_log_set_callback(SILC_LOG_WARNING, silc_log_misc, NULL);
silc_log_set_callback(SILC_LOG_ERROR, silc_log_misc, NULL);
signal_emit("chat protocol deinit", 1,
chat_protocol_find("SILC"));
signal_remove("setup changed", (SIGNAL_FUNC) sig_setup_changed);
+ signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished);
silc_server_deinit();
silc_channels_deinit();
silc_server_connect_to_router_retry,
context, 0, 1, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
- else
+ else {
silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ }
return;
}
/* try to load specified file, if fail stop config parsing */
if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
- SILC_PKCS_FILE_BIN))
+ "", 0, SILC_PKCS_FILE_BIN))
if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
- SILC_PKCS_FILE_PEM)) {
+ "", 0, SILC_PKCS_FILE_PEM)) {
SILC_SERVER_LOG_ERROR(("Error: Could not load private key file."));
return SILC_CONFIG_EPRINTLINE;
}
};
static const SilcConfigTable table_main[] = {
- { "general", SILC_CONFIG_ARG_BLOCK, NULL, table_general },
{ "cipher", SILC_CONFIG_ARG_BLOCK, fetch_cipher, table_cipher },
{ "hash", SILC_CONFIG_ARG_BLOCK, fetch_hash, table_hash },
{ "hmac", SILC_CONFIG_ARG_BLOCK, fetch_hmac, table_hmac },
{ "pkcs", SILC_CONFIG_ARG_BLOCK, fetch_pkcs, table_pkcs },
+ { "general", SILC_CONFIG_ARG_BLOCK, NULL, table_general },
{ "serverinfo", SILC_CONFIG_ARG_BLOCK, fetch_serverinfo, table_serverinfo },
{ "logging", SILC_CONFIG_ARG_BLOCK, NULL, table_logging },
{ "connectionparams", SILC_CONFIG_ARG_BLOCK, fetch_connparam, table_connparam },
silc_hash_register_default();
silc_hmac_register_default();
silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
- opt_identifier, NULL, NULL, NULL, FALSE);
+ opt_identifier, "", NULL, NULL, NULL, FALSE);
exit(0);
}
if (ret == FALSE)
goto fail;
+ /* Register default crypto stuff since we are going to need them
+ in the configuration file parsing phase */
+ silc_cipher_register_default();
+ silc_pkcs_register_default();
+ silc_hash_register_default();
+ silc_hmac_register_default();
+
/* Read configuration files */
silcd->config = silc_server_config_alloc(silcd_config_file);
if (silcd->config == NULL)
goto fail;
silcd->config_file = silcd_config_file;
+ /* Unregister the default crypto stuff so that configuration takes effect */
+ silc_cipher_unregister_all();
+ silc_pkcs_unregister_all();
+ silc_hash_unregister_all();
+ silc_hmac_unregister_all();
+
/* Check for another silcd running */
silc_server_checkpid(silcd);
ret = silc_calloc(buf->len, sizeof(*ret));
memcpy(ret, buf->data, buf->len);
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
return ret;
ret = silc_calloc(buf->len, sizeof(*ret));
memcpy(ret, buf->data, buf->len);
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
return ret;
silc_buffer_unformat(buf,
SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
SILC_STR_END);
- if (ret == -1)
+ if (ret == -1) {
+ SILC_LOG_DEBUG(("Cannot decode private key buffer"));
goto err;
+ }
- if (pkcs_len < 1 || pkcs_len > buf->truelen)
+ if (pkcs_len < 1 || pkcs_len > buf->truelen) {
+ SILC_LOG_DEBUG(("Malformed private key buffer"));
goto err;
+ }
/* See if we support this algorithm (check only if PKCS are registered). */
if (SILC_PKCS_LIST && !silc_pkcs_is_supported(pkcs_name)) {
(check only if PKCS are registered) */
if (SILC_PKCS_LIST) {
silc_pkcs_alloc(pkcs_name, &alg);
- if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
+ if (!alg->pkcs->set_private_key(alg->context, key_data, key_len)) {
+ SILC_LOG_DEBUG(("Could not set private key data"));
goto err;
+ }
silc_pkcs_free(alg);
}
(*private_key)->prv_len = key_len;
}
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
return TRUE;
silc_free(pkcs_name);
if (key_data)
silc_free(key_data);
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
return FALSE;
}
{
unsigned char *data;
SilcUInt32 data_len;
+ bool ret;
data = silc_pkcs_public_key_encode(public_key, &data_len);
- return silc_pkcs_save_public_key_internal(filename, data, data_len,
- encoding);
+ ret = silc_pkcs_save_public_key_internal(filename, data, data_len,
+ encoding);
+ silc_free(data);
+ return ret;
}
/* Saves public key into file */
encoding);
}
+#define SILC_PKCS_PRIVATE_KEY_MAGIC 0x738df531
+
/* Internal routine to save private key. */
static bool silc_pkcs_save_private_key_internal(char *filename,
unsigned char *data,
SilcUInt32 data_len,
+ unsigned char *key,
+ SilcUInt32 key_len,
SilcUInt32 encoding)
{
- SilcBuffer buf;
- SilcUInt32 len;
+ SilcCipher aes;
+ SilcHash md5;
+ SilcHmac sha1hmac;
+ SilcBuffer buf, enc;
+ SilcUInt32 len, blocklen;
+ unsigned char tmp[32], keymat[32];
+ int i;
- switch(encoding) {
+ memset(tmp, 0, sizeof(tmp));
+ memset(keymat, 0, sizeof(keymat));
+
+ /* Allocate the AES cipher */
+ if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
+ SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
+ return FALSE;
+ }
+ blocklen = silc_cipher_get_block_len(aes);
+ if (blocklen * 2 > sizeof(tmp))
+ return FALSE;
+
+ /* Allocate MD5 hash */
+ if (!silc_hash_alloc("md5", &md5)) {
+ SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
+ silc_cipher_free(aes);
+ return FALSE;
+ }
+
+ /* Allocate HMAC */
+ if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+ return FALSE;
+ }
+
+ /* Derive the encryption key from the provided key material. The key
+ is 256 bits length, and derived by taking hash of the data, then
+ re-hashing the data and the previous digest, and using the first and
+ second digest as the key. */
+ silc_hash_init(md5);
+ silc_hash_update(md5, key, key_len);
+ silc_hash_final(md5, keymat);
+ silc_hash_init(md5);
+ silc_hash_update(md5, key, key_len);
+ silc_hash_update(md5, keymat, 16);
+ silc_hash_final(md5, keymat + 16);
+
+ /* Set the key to the cipher */
+ silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
+
+ /* Encode the buffer to be encrypted. Add padding to it too, at least
+ block size of the cipher. */
+
+ /* Allocate buffer for encryption */
+ len = silc_hmac_len(sha1hmac);
+ enc = silc_buffer_alloc_size(data_len + 4 + 4 +
+ (blocklen + (data_len % blocklen)) + len);
+ if (!enc) {
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+ return FALSE;
+ }
+
+ /* Generate padding */
+ for (i = 0; i < blocklen + (data_len % blocklen); i++)
+ tmp[i] = silc_rng_global_get_byte_fast();
+
+ /* Put magic number */
+ SILC_PUT32_MSB(SILC_PKCS_PRIVATE_KEY_MAGIC, enc->data);
+ silc_buffer_pull(enc, 4);
+
+ /* Encode the buffer */
+ silc_buffer_format(enc,
+ SILC_STR_UI_INT(data_len),
+ SILC_STR_UI_XNSTRING(data, data_len),
+ SILC_STR_UI_XNSTRING(tmp, blocklen + (data_len %
+ blocklen)),
+ SILC_STR_END);
+
+ /* Encrypt. */
+ silc_cipher_encrypt(aes, enc->data, enc->data, enc->len - len,
+ silc_cipher_get_iv(aes));
+
+ silc_buffer_push(enc, 4);
+
+ /* Compute HMAC over the encrypted data and append the MAC to data.
+ The key is the first digest of the original key material. */
+ data_len = enc->len - len;
+ silc_hmac_init_with_key(sha1hmac, keymat, 16);
+ silc_hmac_update(sha1hmac, enc->data, data_len);
+ silc_buffer_pull(enc, data_len);
+ silc_hmac_final(sha1hmac, enc->data, NULL);
+ silc_buffer_push(enc, data_len);
+
+ /* Cleanup */
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+
+ data = enc->data;
+ data_len = enc->len;
+
+ switch (encoding) {
case SILC_PKCS_FILE_BIN:
break;
case SILC_PKCS_FILE_PEM:
break;
}
+ /* Encode the data and save to file */
len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
- buf = silc_buffer_alloc(len);
- silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
-
+ buf = silc_buffer_alloc_size(len);
silc_buffer_format(buf,
SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
SILC_STR_UI_XNSTRING(data, data_len),
/* Save into a file */
if (silc_file_writefile_mode(filename, buf->data, buf->len, 0600)) {
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
+ silc_buffer_clear(enc);
+ silc_buffer_free(enc);
return FALSE;
}
+ silc_buffer_clear(buf);
silc_buffer_free(buf);
+ silc_buffer_clear(enc);
+ silc_buffer_free(enc);
return TRUE;
}
/* Saves private key into file. */
-/* XXX The buffer should be encrypted if passphrase is provided. */
bool silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
SilcUInt32 encoding)
{
unsigned char *data;
SilcUInt32 data_len;
+ bool ret;
data = silc_pkcs_private_key_encode(private_key, &data_len);
- return silc_pkcs_save_private_key_internal(filename, data, data_len,
- encoding);
-}
-
-/* Saves private key into file. */
-/* XXX The buffer should be encrypted if passphrase is provided. */
-
-bool silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
- SilcUInt32 data_len,
- unsigned char *passphrase,
- SilcUInt32 encoding)
-{
- return silc_pkcs_save_private_key_internal(filename, data, data_len,
- encoding);
+ ret = silc_pkcs_save_private_key_internal(filename, data, data_len,
+ passphrase, passphrase_len,
+ encoding);
+ memset(data, 0, data_len);
+ silc_free(data);
+ return ret;
}
/* Loads public key from file and allocates new public key. Returns TRUE
/* Load private key from file and allocates new private key. Returns TRUE
if loading was successful. */
-/* XXX Should support encrypted private key files */
bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
+ unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
SilcUInt32 encoding)
{
+ SilcCipher aes;
+ SilcHash md5;
+ SilcHmac sha1hmac;
+ SilcUInt32 blocklen;
+ unsigned char tmp[32], keymat[32];
unsigned char *cp, *old, *data, byte;
- SilcUInt32 i, data_len, len;
+ SilcUInt32 i, data_len, len, magic, mac_len;
old = data = silc_file_readfile(filename, &data_len);
if (!data)
data = cp;
/* Decode private key */
- if (private_key) {
- len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
- strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+ len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+ strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
- switch(encoding) {
- case SILC_PKCS_FILE_BIN:
- break;
- case SILC_PKCS_FILE_PEM:
- data = silc_pem_decode(data, len, &len);
- break;
+ switch(encoding) {
+ case SILC_PKCS_FILE_BIN:
+ break;
+ case SILC_PKCS_FILE_PEM:
+ data = silc_pem_decode(data, len, &len);
+ if (!data) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
}
+ break;
+ }
- if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
+ memset(tmp, 0, sizeof(tmp));
+ memset(keymat, 0, sizeof(keymat));
+
+ /* Private key files without the specific magic number are assumed
+ to be the old-style private keys that are not encrypted. */
+ SILC_GET32_MSB(magic, data);
+ if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) {
+ /* Now decode the actual private key */
+ if (!silc_pkcs_private_key_decode(data, len, private_key)) {
memset(old, 0, data_len);
silc_free(old);
return FALSE;
}
+
+ memset(old, 0, data_len);
+ silc_free(old);
+ return TRUE;
+ }
+
+ /* Allocate the AES cipher */
+ if (!silc_cipher_alloc("aes-256-cbc", &aes)) {
+ SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered"));
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ blocklen = silc_cipher_get_block_len(aes);
+ if (blocklen * 2 > sizeof(tmp)) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ /* Allocate MD5 hash */
+ if (!silc_hash_alloc("md5", &md5)) {
+ SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered"));
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ /* Allocate HMAC */
+ if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) {
+ SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered"));
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+
+ /* Derive the decryption key from the provided key material. The key
+ is 256 bits length, and derived by taking hash of the data, then
+ re-hashing the data and the previous digest, and using the first and
+ second digest as the key. */
+ silc_hash_init(md5);
+ silc_hash_update(md5, passphrase, passphrase_len);
+ silc_hash_final(md5, keymat);
+ silc_hash_init(md5);
+ silc_hash_update(md5, passphrase, passphrase_len);
+ silc_hash_update(md5, keymat, 16);
+ silc_hash_final(md5, keymat + 16);
+
+ /* Set the key to the cipher */
+ silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8);
+
+ /* First, verify the MAC of the private key data */
+ mac_len = silc_hmac_len(sha1hmac);
+ silc_hmac_init_with_key(sha1hmac, keymat, 16);
+ silc_hmac_update(sha1hmac, data, len - mac_len);
+ silc_hmac_final(sha1hmac, tmp, NULL);
+ if (memcmp(tmp, data + (len - mac_len), mac_len)) {
+ SILC_LOG_DEBUG(("Integrity check for private key failed"));
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ data += 4;
+ len -= 4;
+
+ /* Decrypt the private key buffer */
+ silc_cipher_decrypt(aes, data, data, len - mac_len, silc_cipher_get_iv(aes));
+ SILC_GET32_MSB(i, data);
+ if (i > len) {
+ SILC_LOG_DEBUG(("Bad private key length in buffer!"));
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
+ }
+ data += 4;
+ len = i;
+
+ /* Cleanup */
+ memset(keymat, 0, sizeof(keymat));
+ memset(tmp, 0, sizeof(tmp));
+ silc_hmac_free(sha1hmac);
+ silc_hash_free(md5);
+ silc_cipher_free(aes);
+
+ /* Now decode the actual private key */
+ if (!silc_pkcs_private_key_decode(data, len, private_key)) {
+ memset(old, 0, data_len);
+ silc_free(old);
+ return FALSE;
}
memset(old, 0, data_len);
*
* DESCRIPTION
*
- * Saves public key into file. Returns FALSE on error.
+ * Saves public key into file. The public key is already encoded as
+ * data when calling this function. Returns FALSE on error.
*
***/
bool silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
* SYNOPSIS
*
* bool silc_pkcs_save_private_key(char *filename,
- * SilcPrivateKey private_key,
- * unsigned char *passphrase,
- * SilcUInt32 encoding);
+ * SilcPrivateKey private_key,
+ * unsigned char *passphrase,
+ * SilcUInt32 passphrase_len,
+ * SilcUInt32 encoding);
*
* DESCRIPTION
*
- * Saves private key into file. Returns FALSE on error.
+ * Saves private key into file. The private key is encrypted into
+ * the file with the `passphrase' as a key. The encryption algorithm
+ * is AES with 256 bit key in CBC mode. Returns FALSE on error.
*
***/
bool silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key,
unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
SilcUInt32 encoding);
-/****f* silccrypt/SilcPKCSAPI/silc_pkcs_save_private_key_data
- *
- * SYNOPSIS
- *
- * bool silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
- * SilcUInt32 data_len,
- * unsigned char *passphrase,
- * SilcUInt32 encoding);
- *
- * DESCRIPTION
- *
- * Saves private key into file. Returns FALSE on error.
- *
- ***/
-bool silc_pkcs_save_private_key_data(char *filename, unsigned char *data,
- SilcUInt32 data_len,
- unsigned char *passphrase,
- SilcUInt32 encoding);
-
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_load_public_key
*
* SYNOPSIS
* SYNOPSIS
*
* bool silc_pkcs_load_private_key(char *filename,
- * SilcPrivateKey *private_key,
- * SilcUInt32 encoding);
+ * SilcPrivateKey *private_key,
+ * unsigned char *passphrase,
+ * SilcUInt32 passphrase_len,
+ * SilcUInt32 encoding);
*
* DESCRIPTION
*
* Load private key from file and allocates new private key. Returns TRUE
- * if loading was successful.
+ * if loading was successful. The `passphrase' is used as decryption
+ * key of the private key file.
*
***/
bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
+ unsigned char *passphrase,
+ SilcUInt32 passphrase_len,
SilcUInt32 encoding);
#endif /* SILCPKCS_H */
const char *pub_filename,
const char *prv_filename,
const char *pub_identifier,
+ const char *passphrase,
SilcPKCS *return_pkcs,
SilcPublicKey *return_public_key,
SilcPrivateKey *return_private_key,
char *prvfile = prv_filename ? strdup(prv_filename) : NULL;
char *alg = pkcs_name ? strdup(pkcs_name) : NULL;
char *identifier = pub_identifier ? strdup(pub_identifier) : NULL;
+ char *pass = passphrase ? strdup(passphrase) : NULL;
if (interactive && (!alg || !pub_filename || !prv_filename))
printf("\
if (!pkfile) {
if (interactive) {
memset(line, 0, sizeof(line));
- snprintf(line, sizeof(line), "Public key filename [public_key.pub] ");
+ snprintf(line, sizeof(line), "Public key filename [public_key.pub]: ");
pkfile = silc_get_input(line, FALSE);
}
if (!pkfile)
if (!prvfile) {
if (interactive) {
memset(line, 0, sizeof(line));
- snprintf(line, sizeof(line), "Public key filename [private_key.prv] ");
+ snprintf(line, sizeof(line), "Private key filename [private_key.prv]: ");
prvfile = silc_get_input(line, FALSE);
}
if (!prvfile)
prvfile = strdup("private_key.prv");
}
+ if (!pass) {
+ memset(line, 0, sizeof(line));
+ snprintf(line, sizeof(line), "Private key passphrase: ");
+ pass = silc_get_input(line, TRUE);
+ if (!pass)
+ pass = strdup("");
+ }
+
/* Generate keys */
silc_pkcs_alloc(alg, &pkcs);
silc_pkcs_generate_key(pkcs, key_len_bits, rng);
key = silc_pkcs_get_private_key(pkcs, &key_len);
prv_key = silc_pkcs_private_key_alloc(silc_pkcs_get_name(pkcs),
key, key_len);
- silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
+ silc_pkcs_save_private_key(prvfile, prv_key,
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_BIN);
if (return_private_key)
*return_private_key = prv_key;
else
silc_free(pkfile);
silc_free(prvfile);
silc_free(identifier);
+ memset(pass, 0, strlen(pass));
+ silc_free(pass);
return TRUE;
}
bool silc_load_key_pair(const char *pub_filename,
const char *prv_filename,
+ const char *passphrase,
SilcPKCS *return_pkcs,
SilcPublicKey *return_public_key,
SilcPrivateKey *return_private_key)
{
+ char *pass = passphrase ? strdup(passphrase) : NULL;
+
SILC_LOG_DEBUG(("Loading public and private keys"));
if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
SILC_PKCS_FILE_PEM) == FALSE)
if (silc_pkcs_load_public_key((char *)pub_filename, return_public_key,
- SILC_PKCS_FILE_BIN) == FALSE)
+ SILC_PKCS_FILE_BIN) == FALSE) {
+ memset(pass, 0, strlen(pass));
return FALSE;
+ }
+
+ if (!pass) {
+ pass = silc_get_input("Private key passphrase: ", TRUE);
+ if (!pass)
+ pass = strdup("");
+ }
if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
+ (unsigned char *)pass, strlen(pass),
SILC_PKCS_FILE_BIN) == FALSE)
if (silc_pkcs_load_private_key((char *)prv_filename, return_private_key,
- SILC_PKCS_FILE_PEM) == FALSE)
+ (unsigned char *)pass, strlen(pass),
+ SILC_PKCS_FILE_PEM) == FALSE) {
+ memset(pass, 0, strlen(pass));
return FALSE;
+ }
if (return_pkcs) {
silc_pkcs_alloc((*return_public_key)->name, return_pkcs);
silc_pkcs_private_key_set(*return_pkcs, *return_private_key);
}
+ memset(pass, 0, strlen(pass));
return TRUE;
}
* const char *pub_filename,
* const char *prv_filename,
* const char *pub_identifier,
+ * const char *passphrase,
* SilcPKCS *return_pkcs,
* SilcPublicKey *return_public_key,
* SilcPrivateKey *return_private_key,
* "UN=foobar, HN=hostname"), or if NULL the routine generates it
* automatically.
*
+ * The `passphrase' is the passphrase that is used to encrypt the
+ * private key file. It is recommended that you would protect your
+ * private key file with a passphrase.
+ *
* The routine returns FALSE if error occurs during key generation.
* Function returns TRUE when success and returns the created SilcPKCS
* object, which can be used to perform public key cryptography into
const char *pub_filename,
const char *prv_filename,
const char *pub_identifier,
+ const char *passphrase,
SilcPKCS *return_pkcs,
SilcPublicKey *return_public_key,
SilcPrivateKey *return_private_key,
* bool silc_load_key_pair(const char *pub_filename,
* const char *prv_filename,
* SilcPKCS *return_pkcs,
+ * const char *passphrase,
* SilcPublicKey *return_public_key,
* SilcPrivateKey *return_private_key);
*
* public key into `return_public_key' pointer, private key into
* `return_private_key' pointer and the SilcPKCS object to the
* `return_pkcs'. The SilcPKCS can be used to perform public key
- * cryptographic operations.
+ * cryptographic operations. The `passphrase' is the passphrase
+ * which will be used to decrypt the private key file.
*
***/
bool silc_load_key_pair(const char *pub_filename,
const char *prv_filename,
+ const char *passphrase,
SilcPKCS *return_pkcs,
SilcPublicKey *return_public_key,
SilcPrivateKey *return_private_key);