version 1.4, 2014/01/31 16:39:19 |
version 1.5, 2014/06/24 01:13:21 |
|
|
#include <stdio.h> /* needed for misc.h */ |
#include <stdio.h> /* needed for misc.h */ |
|
|
#include "log.h" |
#include "log.h" |
#include "misc.h" |
#include "sshbuf.h" |
|
#include "ssherr.h" |
#include "cipher-chachapoly.h" |
#include "cipher-chachapoly.h" |
|
|
void chachapoly_init(struct chachapoly_ctx *ctx, |
int chachapoly_init(struct chachapoly_ctx *ctx, |
const u_char *key, u_int keylen) |
const u_char *key, u_int keylen) |
{ |
{ |
if (keylen != (32 + 32)) /* 2 x 256 bit keys */ |
if (keylen != (32 + 32)) /* 2 x 256 bit keys */ |
fatal("%s: invalid keylen %u", __func__, keylen); |
return SSH_ERR_INVALID_ARGUMENT; |
chacha_keysetup(&ctx->main_ctx, key, 256); |
chacha_keysetup(&ctx->main_ctx, key, 256); |
chacha_keysetup(&ctx->header_ctx, key + 32, 256); |
chacha_keysetup(&ctx->header_ctx, key + 32, 256); |
|
return 0; |
} |
} |
|
|
/* |
/* |
|
|
u_char seqbuf[8]; |
u_char seqbuf[8]; |
const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ |
const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ |
u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; |
u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; |
int r = -1; |
int r = SSH_ERR_INTERNAL_ERROR; |
|
|
/* |
/* |
* Run ChaCha20 once to generate the Poly1305 key. The IV is the |
* Run ChaCha20 once to generate the Poly1305 key. The IV is the |
* packet sequence number. |
* packet sequence number. |
*/ |
*/ |
memset(poly_key, 0, sizeof(poly_key)); |
memset(poly_key, 0, sizeof(poly_key)); |
put_u64(seqbuf, seqnr); |
POKE_U64(seqbuf, seqnr); |
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); |
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); |
chacha_encrypt_bytes(&ctx->main_ctx, |
chacha_encrypt_bytes(&ctx->main_ctx, |
poly_key, poly_key, sizeof(poly_key)); |
poly_key, poly_key, sizeof(poly_key)); |
|
|
const u_char *tag = src + aadlen + len; |
const u_char *tag = src + aadlen + len; |
|
|
poly1305_auth(expected_tag, src, aadlen + len, poly_key); |
poly1305_auth(expected_tag, src, aadlen + len, poly_key); |
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) |
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { |
|
r = SSH_ERR_MAC_INVALID; |
goto out; |
goto out; |
|
} |
} |
} |
/* Crypt additional data */ |
/* Crypt additional data */ |
if (aadlen) { |
if (aadlen) { |
|
|
poly_key); |
poly_key); |
} |
} |
r = 0; |
r = 0; |
|
|
out: |
out: |
explicit_bzero(expected_tag, sizeof(expected_tag)); |
explicit_bzero(expected_tag, sizeof(expected_tag)); |
explicit_bzero(seqbuf, sizeof(seqbuf)); |
explicit_bzero(seqbuf, sizeof(seqbuf)); |
|
|
u_char buf[4], seqbuf[8]; |
u_char buf[4], seqbuf[8]; |
|
|
if (len < 4) |
if (len < 4) |
return -1; /* Insufficient length */ |
return SSH_ERR_MESSAGE_INCOMPLETE; |
put_u64(seqbuf, seqnr); |
POKE_U64(seqbuf, seqnr); |
chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); |
chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); |
chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); |
chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); |
*plenp = get_u32(buf); |
*plenp = PEEK_U32(buf); |
return 0; |
return 0; |
} |
} |
|
|