openssh/cipher-3des1.c

156 lines
4.2 KiB
C
Raw Normal View History

/* $OpenBSD: cipher-3des1.c,v 1.12 2015/01/14 10:24:42 markus Exp $ */
/*
* Copyright (c) 2003 Markus Friedl. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
- deraadt@cvs.openbsd.org 2006/08/03 03:34:42 [OVERVIEW atomicio.c atomicio.h auth-bsdauth.c auth-chall.c auth-krb5.c] [auth-options.c auth-options.h auth-passwd.c auth-rh-rsa.c auth-rhosts.c] [auth-rsa.c auth-skey.c auth.c auth.h auth1.c auth2-chall.c auth2-gss.c] [auth2-hostbased.c auth2-kbdint.c auth2-none.c auth2-passwd.c ] [auth2-pubkey.c auth2.c authfd.c authfd.h authfile.c bufaux.c bufbn.c] [buffer.c buffer.h canohost.c channels.c channels.h cipher-3des1.c] [cipher-bf1.c cipher-ctr.c cipher.c cleanup.c clientloop.c compat.c] [compress.c deattack.c dh.c dispatch.c dns.c dns.h fatal.c groupaccess.c] [groupaccess.h gss-genr.c gss-serv-krb5.c gss-serv.c hostfile.c kex.c] [kex.h kexdh.c kexdhc.c kexdhs.c kexgex.c kexgexc.c kexgexs.c key.c] [key.h log.c log.h mac.c match.c md-sha256.c misc.c misc.h moduli.c] [monitor.c monitor_fdpass.c monitor_mm.c monitor_mm.h monitor_wrap.c] [monitor_wrap.h msg.c nchan.c packet.c progressmeter.c readconf.c] [readconf.h readpass.c rsa.c scard.c scard.h scp.c servconf.c servconf.h] [serverloop.c session.c session.h sftp-client.c sftp-common.c] [sftp-common.h sftp-glob.c sftp-server.c sftp.c ssh-add.c ssh-agent.c] [ssh-dss.c ssh-gss.h ssh-keygen.c ssh-keyscan.c ssh-keysign.c ssh-rsa.c] [ssh.c ssh.h sshconnect.c sshconnect.h sshconnect1.c sshconnect2.c] [sshd.c sshlogin.c sshlogin.h sshpty.c sshpty.h sshtty.c ttymodes.c] [uidswap.c uidswap.h uuencode.c uuencode.h xmalloc.c xmalloc.h] [loginrec.c loginrec.h openbsd-compat/port-aix.c openbsd-compat/port-tun.h] almost entirely get rid of the culture of ".h files that include .h files" ok djm, sort of ok stevesk makes the pain stop in one easy step NB. portable commit contains everything *except* removing includes.h, as that will take a fair bit more work as we move headers that are required for portability workarounds to defines.h. (also, this step wasn't "easy")
2006-08-05 02:39:39 +00:00
#include <sys/types.h>
#include <string.h>
#include <openssl/evp.h>
#include "ssherr.h"
/*
* This is used by SSH1:
*
* What kind of triple DES are these 2 routines?
*
* Why is there a redundant initialization vector?
*
* If only iv3 was used, then, this would till effect have been
* outer-cbc. However, there is also a private iv1 == iv2 which
* perhaps makes differential analysis easier. On the other hand, the
* private iv1 probably makes the CRC-32 attack ineffective. This is a
* result of that there is no longer any known iv1 to use when
* choosing the X block.
*/
struct ssh1_3des_ctx
{
EVP_CIPHER_CTX k1, k2, k3;
};
const EVP_CIPHER * evp_ssh1_3des(void);
int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
static int
ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
int enc)
{
struct ssh1_3des_ctx *c;
u_char *k1, *k2, *k3;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
if ((c = calloc(1, sizeof(*c))) == NULL)
return 0;
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
if (key == NULL)
return 1;
if (enc == -1)
enc = ctx->encrypt;
k1 = k2 = k3 = (u_char *) key;
k2 += 8;
if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
if (enc)
k3 += 16;
else
k1 += 16;
}
EVP_CIPHER_CTX_init(&c->k1);
EVP_CIPHER_CTX_init(&c->k2);
EVP_CIPHER_CTX_init(&c->k3);
if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
explicit_bzero(c, sizeof(*c));
free(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
return 0;
}
return 1;
}
static int
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
{
struct ssh1_3des_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
return 0;
if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
EVP_Cipher(&c->k3, dest, dest, len) == 0)
return 0;
return 1;
}
static int
ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
{
struct ssh1_3des_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
EVP_CIPHER_CTX_cleanup(&c->k1);
EVP_CIPHER_CTX_cleanup(&c->k2);
EVP_CIPHER_CTX_cleanup(&c->k3);
explicit_bzero(c, sizeof(*c));
free(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
}
return 1;
}
int
ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
{
struct ssh1_3des_ctx *c;
if (len != 24)
return SSH_ERR_INVALID_ARGUMENT;
if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
return SSH_ERR_INTERNAL_ERROR;
if (doset) {
memcpy(c->k1.iv, iv, 8);
memcpy(c->k2.iv, iv + 8, 8);
memcpy(c->k3.iv, iv + 16, 8);
} else {
memcpy(iv, c->k1.iv, 8);
memcpy(iv + 8, c->k2.iv, 8);
memcpy(iv + 16, c->k3.iv, 8);
}
return 0;
}
const EVP_CIPHER *
evp_ssh1_3des(void)
{
static EVP_CIPHER ssh1_3des;
memset(&ssh1_3des, 0, sizeof(ssh1_3des));
ssh1_3des.nid = NID_undef;
ssh1_3des.block_size = 8;
ssh1_3des.iv_len = 0;
ssh1_3des.key_len = 16;
ssh1_3des.init = ssh1_3des_init;
ssh1_3des.cleanup = ssh1_3des_cleanup;
ssh1_3des.do_cipher = ssh1_3des_cbc;
ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
return &ssh1_3des;
}