/*
- * Copyright (C) 2011-2012 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
#include "crypt.h"
#include "crypt_backend.h"
#include "fd.h"
+#include "base64.h"
//#define GCRYPT_DEBUG 1
{
int i;
- fprintf(stderr, "%s (%u bytes): ", msg, len);
+ fprintf(stderr, "%s (%d bytes): ", msg, len);
for (i = 0; i < len; i++)
fprintf(stderr, "%02x ", buf[i]);
fprintf(stderr, "\n");
}
/** S-expression for the public part of an RSA key. */
-#define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))"
+#define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))"
/** S-expression for a private RSA key. */
#define RSA_PRIVKEY_SEXP "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))"
{
gcry_error_t gret;
gcry_md_hd_t handle;
- size_t n;;
+ size_t n;
unsigned char *md;
unsigned char octet_string[4], *rp = result, *end = rp + result_len;
ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
if (ret < 0)
- return ret;
+ goto out;
ret = -E_KEY_MARKER;
if (strncmp(map, header_str, strlen(header_str)))
goto unmap;
key[j++] = begin[i];
}
key[j] = '\0';
- //PARA_CRIT_LOG("key: %s\n", key);
- blob_size = key_size * 2;
- blob = para_malloc(blob_size);
- ret = base64_decode(key, blob, blob_size);
+ ret = base64_decode(key, j, (char **)&blob, &blob_size);
free(key);
if (ret < 0)
goto free_unmap;
+ ret = blob_size;
goto unmap;
free_unmap:
free(blob);
free(blob);
blob = NULL;
}
+out:
*result = blob;
return ret;
}
/* bit 6 has value 0 */
static inline bool is_primitive(unsigned char c)
{
- return ((c & (1<<6)) == 0);
+ return (c & (1<<6)) == 0;
}
static inline bool is_primitive_integer(unsigned char c)
{
if (!is_primitive(c))
return false;
- return ((c & 0x1f) == ASN1_TYPE_INTEGER);
+ return (c & 0x1f) == ASN1_TYPE_INTEGER;
}
/* Bit 8 is zero (and bits 7-1 give the length) */
return c & 0x7f;
}
-static int find_pubkey_bignum_offset(const unsigned char *data, int len)
-{
- const unsigned char *p = data, *end = data + len;
-
- /* the whole thing istarts with one sequence */
- if (*p != ASN1_TYPE_SEQUENCE)
- return -E_ASN1_PARSE;
- p++;
- if (p >= end)
- return -E_ASN1_PARSE;
- if (is_short_form(*p))
- p++;
- else
- p += 1 + get_long_form_num_length_bytes(*p);
- if (p >= end)
- return -E_ASN1_PARSE;
- /* another sequence containing the object id, skip it */
- if (*p != ASN1_TYPE_SEQUENCE)
- return -E_ASN1_PARSE;
- p++;
- if (p >= end)
- return -E_ASN1_PARSE;
- if (!is_short_form(*p))
- return -E_ASN1_PARSE;
- p += 1 + get_short_form_length(*p);
- if (p >= end)
- return -E_ASN1_PARSE;
- /* all numbers are wrapped in a bit string object that follows */
- if (*p != ASN1_TYPE_BIT_STRING)
- return -E_ASN1_PARSE;
- p++;
- if (p >= end)
- return -E_ASN1_PARSE;
- if (is_short_form(*p))
- p++;
- else
- p += 1 + get_long_form_num_length_bytes(*p);
- p++; /* skip number of unused bits in the bit string */
- if (p >= end)
- return -E_ASN1_PARSE;
-
- /* next, we have a sequence of two integers (n and e) */
- if (*p != ASN1_TYPE_SEQUENCE)
- return -E_ASN1_PARSE;
- p++;
- if (p >= end)
- return -E_ASN1_PARSE;
- if (is_short_form(*p))
- p++;
- else
- p += 1 + get_long_form_num_length_bytes(*p);
- if (p >= end)
- return -E_ASN1_PARSE;
- if (*p != ASN1_TYPE_INTEGER)
- return -E_ASN1_PARSE;
- return p - data;
-}
-
/*
* Returns: Number of bytes scanned. This may differ from the value returned via
* bn_bytes because the latter does not include the ASN.1 prefix and a leading
for (i = 0; i < num_bytes; i++, cp++)
bn_size = (bn_size << 8) + *cp;
}
- PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, bn_size);
+ PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, (unsigned)bn_size);
gret = gcry_mpi_scan(bn, GCRYMPI_FMT_STD, cp, bn_size, NULL);
if (gret) {
PARA_ERROR_LOG("%s while scanning n\n",
if (p >= end)
return -E_ASN1_PARSE;
- /* Skip next integer */
+ /* skip next integer */
if (*p != ASN1_TYPE_INTEGER)
return -E_ASN1_PARSE;
p++;
gcry_sexp_t sexp;
struct asymmetric_key *key;
+ *result = NULL;
ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER,
&blob);
if (ret < 0)
ret = read_bignum(cp, end, &u, NULL);
if (ret < 0)
goto release_q;
- cp += ret;
/*
* OpenSSL uses slightly different parameters than gcrypt. To use these
* parameters we need to swap the values of p and q and recompute u.
return ret;
}
-/** Public keys start with this header. */
-#define PUBLIC_KEY_HEADER "-----BEGIN PUBLIC KEY-----"
-/** Public keys end with this footer. */
-#define PUBLIC_KEY_FOOTER "-----END PUBLIC KEY-----"
-
-static int get_asn_public_key(const char *key_file, struct asymmetric_key **result)
-{
- gcry_mpi_t n = NULL, e = NULL;
- unsigned char *blob, *cp, *end;
- int blob_size, ret, n_size;
- gcry_error_t gret;
- size_t erroff;
- gcry_sexp_t sexp;
- struct asymmetric_key *key;
-
- ret = decode_key(key_file, PUBLIC_KEY_HEADER, PUBLIC_KEY_FOOTER,
- &blob);
- if (ret < 0)
- return ret;
- blob_size = ret;
- end = blob + blob_size;
- ret = find_pubkey_bignum_offset(blob, blob_size);
- if (ret < 0)
- goto free_blob;
- PARA_DEBUG_LOG("decoding public RSA params at offset %d\n", ret);
- cp = blob + ret;
-
- ret = read_bignum(cp, end, &n, &n_size);
- if (ret < 0)
- goto free_blob;
- cp += ret;
-
- ret = read_bignum(cp, end, &e, NULL);
- if (ret < 0)
- goto release_n;
- cp += ret;
-
- gret = gcry_sexp_build(&sexp, &erroff, RSA_PUBKEY_SEXP, n, e);
- if (gret) {
- PARA_ERROR_LOG("offset %zu: %s\n", erroff,
- gcry_strerror(gcry_err_code(gret)));
- ret = -E_SEXP_BUILD;
- goto release_e;
- }
- key = para_malloc(sizeof(*key));
- key->sexp = sexp;
- *result = key;
- ret = n_size;
- PARA_INFO_LOG("successfully read %u bit asn public key\n", n_size * 8);
-
-release_e:
- gcry_mpi_release(e);
-release_n:
- gcry_mpi_release(n);
-free_blob:
- free(blob);
- return ret;
-}
-
static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result)
{
int ret;
size_t nr_scanned, erroff, decoded_size;
gcry_mpi_t e = NULL, n = NULL;
- PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
- if (size > INT_MAX / 4)
- return -ERRNO_TO_PARA_ERROR(EOVERFLOW);
- blob = para_malloc(2 * size);
- ret = uudecode((char *)data, blob, 2 * size);
+ PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
+ ret = uudecode((char *)data, size, (char **)&blob, &decoded_size);
if (ret < 0)
goto free_blob;
- decoded_size = ret;
end = blob + decoded_size;
dump_buffer("decoded key", blob, decoded_size);
ret = check_ssh_key_header(blob, decoded_size);
goto release_n;
}
ret = nr_scanned / 32 * 32;
- PARA_INFO_LOG("successfully read %u bit ssh public key\n", ret * 8);
+ PARA_INFO_LOG("successfully read %d bit ssh public key\n", ret * 8);
release_n:
gcry_mpi_release(n);
release_e:
return ret;
}
-int get_asymmetric_key(const char *key_file, int private,
- struct asymmetric_key **result)
+int get_public_key(const char *key_file, struct asymmetric_key **result)
{
int ret, ret2;
void *map;
gcry_sexp_t sexp;
struct asymmetric_key *key;
- if (private)
- return get_private_key(key_file, result);
ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
if (ret < 0)
return ret;
ret = is_ssh_rsa_key(map, map_size);
if (!ret) {
- ret = para_munmap(map, map_size);
- if (ret < 0)
- return ret;
- return get_asn_public_key(key_file, result);
+ para_munmap(map, map_size);
+ return -E_SSH_PARSE;
}
start = map + ret;
end = map + map_size;
key->num_bytes = ret;
key->sexp = sexp;
*result = key;
- ret = key->num_bytes;
unmap:
ret2 = para_munmap(map, map_size);
if (ret >= 0 && ret2 < 0)
return ret;
}
-void free_asymmetric_key(struct asymmetric_key *key)
+void free_public_key(struct asymmetric_key *key)
{
if (!key)
return;
PARA_DEBUG_LOG("decrypted buffer before unpad (%d bytes):\n",
key_size);
- dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);;
+ dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);
ret = unpad_oaep(oaep_buf, key_size, outbuf, nbytes);
if (ret < 0)
goto out_mpi_release;
PARA_DEBUG_LOG("decrypted buffer after unpad (%zu bytes):\n",
*nbytes);
- dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);;
+ dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);
ret = 1;
out_mpi_release:
gcry_mpi_release(out_mpi);
gcry_sexp_t in, out, priv_key;
size_t nbytes;
+ ret = check_private_key_file(key_file);
+ if (ret < 0)
+ return ret;
PARA_INFO_LOG("decrypting %d byte input\n", inlen);
/* key_file -> asymmetric key priv */
ret = get_private_key(key_file, &priv);
key_release:
gcry_sexp_release(priv_key);
free_key:
- free_asymmetric_key(priv);
+ gcry_sexp_release(priv->sexp);
+ free(priv);
return ret;
}
gcry_cipher_hd_t handle;
};
-struct stream_cipher *sc_new(const unsigned char *data, int len)
+struct stream_cipher *sc_new(const unsigned char *data, int len,
+ bool use_aes)
{
gcry_error_t gret;
-
struct stream_cipher *sc = para_malloc(sizeof(*sc));
+
+ if (use_aes) {
+ assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
+ gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,
+ GCRY_CIPHER_MODE_CTR, 0);
+ assert(gret == 0);
+ gret = gcry_cipher_setkey(sc->handle, data,
+ AES_CRT128_BLOCK_SIZE);
+ assert(gret == 0);
+ gret = gcry_cipher_setctr(sc->handle,
+ data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
+ assert(gret == 0);
+ return sc;
+ }
gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR,
GCRY_CIPHER_MODE_STREAM, 0);
if (gret) {
free(sc);
}
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
-{
- gcry_error_t gret;
- int ret;
- unsigned char *tmp = para_malloc(size);
-
- assert(size);
- gret = gcry_cipher_encrypt(scc->send->handle, tmp, size,
- (unsigned char *)buf, size);
- assert(gret == 0);
- ret = write_all(scc->fd, (char *)tmp, &size);
- free(tmp);
- return ret;
-}
-
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
+void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
{
+ gcry_cipher_hd_t handle = sc->handle;
gcry_error_t gret;
- ssize_t ret = recv(scc->fd, buf, size, 0);
- if (ret < 0)
- ret = -ERRNO_TO_PARA_ERROR(errno);
- if (ret <= 0)
- return ret;
/* perform in-place encryption */
- gret = gcry_cipher_encrypt(scc->recv->handle, (unsigned char *)buf, ret,
+ *dst = *src;
+ gret = gcry_cipher_encrypt(handle, src->iov_base, src->iov_len,
NULL, 0);
assert(gret == 0);
- return ret;
}