1261287Sdes/* 2261287Sdes * Copyright (c) 2013 Damien Miller <djm@mindrot.org> 3261287Sdes * 4261287Sdes * Permission to use, copy, modify, and distribute this software for any 5261287Sdes * purpose with or without fee is hereby granted, provided that the above 6261287Sdes * copyright notice and this permission notice appear in all copies. 7261287Sdes * 8261287Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9261287Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10261287Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11261287Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12261287Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13261287Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14261287Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15261287Sdes */ 16261287Sdes 17295367Sdes/* $OpenBSD: cipher-chachapoly.c,v 1.7 2015/01/14 10:24:42 markus Exp $ */ 18261287Sdes 19261287Sdes#include "includes.h" 20261287Sdes 21261287Sdes#include <sys/types.h> 22261287Sdes#include <stdarg.h> /* needed for log.h */ 23261287Sdes#include <string.h> 24261287Sdes#include <stdio.h> /* needed for misc.h */ 25261287Sdes 26261287Sdes#include "log.h" 27295367Sdes#include "sshbuf.h" 28295367Sdes#include "ssherr.h" 29261287Sdes#include "cipher-chachapoly.h" 30261287Sdes 31295367Sdesint chachapoly_init(struct chachapoly_ctx *ctx, 32261287Sdes const u_char *key, u_int keylen) 33261287Sdes{ 34261287Sdes if (keylen != (32 + 32)) /* 2 x 256 bit keys */ 35295367Sdes return SSH_ERR_INVALID_ARGUMENT; 36261287Sdes chacha_keysetup(&ctx->main_ctx, key, 256); 37261287Sdes chacha_keysetup(&ctx->header_ctx, key + 32, 256); 38295367Sdes return 0; 39261287Sdes} 40261287Sdes 41261287Sdes/* 42261287Sdes * chachapoly_crypt() operates as following: 43261287Sdes * En/decrypt with header key 'aadlen' bytes from 'src', storing result 44261287Sdes * to 'dest'. The ciphertext here is treated as additional authenticated 45261287Sdes * data for MAC calculation. 46261287Sdes * En/decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. Use 47261287Sdes * POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the authentication 48261287Sdes * tag. This tag is written on encryption and verified on decryption. 49261287Sdes */ 50261287Sdesint 51261287Sdeschachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, 52261287Sdes const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) 53261287Sdes{ 54261287Sdes u_char seqbuf[8]; 55261287Sdes const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ 56261287Sdes u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; 57295367Sdes int r = SSH_ERR_INTERNAL_ERROR; 58261287Sdes 59261287Sdes /* 60261287Sdes * Run ChaCha20 once to generate the Poly1305 key. The IV is the 61261287Sdes * packet sequence number. 62261287Sdes */ 63264377Sdes memset(poly_key, 0, sizeof(poly_key)); 64295367Sdes POKE_U64(seqbuf, seqnr); 65261287Sdes chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); 66261287Sdes chacha_encrypt_bytes(&ctx->main_ctx, 67261287Sdes poly_key, poly_key, sizeof(poly_key)); 68261287Sdes 69261287Sdes /* If decrypting, check tag before anything else */ 70261287Sdes if (!do_encrypt) { 71261287Sdes const u_char *tag = src + aadlen + len; 72261287Sdes 73261287Sdes poly1305_auth(expected_tag, src, aadlen + len, poly_key); 74295367Sdes if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { 75295367Sdes r = SSH_ERR_MAC_INVALID; 76261287Sdes goto out; 77295367Sdes } 78261287Sdes } 79295367Sdes 80261287Sdes /* Crypt additional data */ 81261287Sdes if (aadlen) { 82261287Sdes chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); 83261287Sdes chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); 84261287Sdes } 85295367Sdes 86295367Sdes /* Set Chacha's block counter to 1 */ 87295367Sdes chacha_ivsetup(&ctx->main_ctx, seqbuf, one); 88261287Sdes chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, 89261287Sdes dest + aadlen, len); 90261287Sdes 91261287Sdes /* If encrypting, calculate and append tag */ 92261287Sdes if (do_encrypt) { 93261287Sdes poly1305_auth(dest + aadlen + len, dest, aadlen + len, 94261287Sdes poly_key); 95261287Sdes } 96261287Sdes r = 0; 97261287Sdes out: 98264377Sdes explicit_bzero(expected_tag, sizeof(expected_tag)); 99264377Sdes explicit_bzero(seqbuf, sizeof(seqbuf)); 100264377Sdes explicit_bzero(poly_key, sizeof(poly_key)); 101261287Sdes return r; 102261287Sdes} 103261287Sdes 104261287Sdes/* Decrypt and extract the encrypted packet length */ 105261287Sdesint 106261287Sdeschachapoly_get_length(struct chachapoly_ctx *ctx, 107261287Sdes u_int *plenp, u_int seqnr, const u_char *cp, u_int len) 108261287Sdes{ 109261287Sdes u_char buf[4], seqbuf[8]; 110261287Sdes 111261287Sdes if (len < 4) 112295367Sdes return SSH_ERR_MESSAGE_INCOMPLETE; 113295367Sdes POKE_U64(seqbuf, seqnr); 114261287Sdes chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); 115261287Sdes chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); 116295367Sdes *plenp = PEEK_U32(buf); 117261287Sdes return 0; 118261287Sdes} 119