mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-05-28 17:41:28 +03:00
[crypto] initial support for ecdh-sha2-nistp256
Works with openssl Still requires work for libgcrypt and other modes
This commit is contained in:
parent
3b72bf0880
commit
c5a998f47a
@ -35,6 +35,10 @@
|
||||
/* Define to 1 if you have the <openssl/des.h> header file. */
|
||||
#cmakedefine HAVE_OPENSSL_DES_H 1
|
||||
|
||||
/* Define to 1 if you have the <openssl/ecdh.h> header file. */
|
||||
#cmakedefine HAVE_OPENSSL_ECDH_H 1
|
||||
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file. */
|
||||
#cmakedefine HAVE_PTHREAD_H 1
|
||||
|
||||
|
@ -40,18 +40,31 @@
|
||||
#undef cbc_decrypt
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
#include <openssl/ecdh.h>
|
||||
#endif
|
||||
|
||||
enum ssh_key_exchange_e {
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
SSH_KEX_DH_GROUP1_SHA1=1,
|
||||
/* ecdh-sha2-nistp256 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP256
|
||||
};
|
||||
|
||||
struct ssh_crypto_struct {
|
||||
bignum e,f,x,k,y;
|
||||
unsigned char session_id[SHA_DIGEST_LEN];
|
||||
|
||||
unsigned char encryptIV[SHA_DIGEST_LEN*2];
|
||||
unsigned char decryptIV[SHA_DIGEST_LEN*2];
|
||||
|
||||
unsigned char decryptkey[SHA_DIGEST_LEN*2];
|
||||
unsigned char encryptkey[SHA_DIGEST_LEN*2];
|
||||
|
||||
unsigned char encryptMAC[SHA_DIGEST_LEN];
|
||||
unsigned char decryptMAC[SHA_DIGEST_LEN];
|
||||
EC_KEY *ecdh_privkey;
|
||||
ssh_string ecdh_client_pubkey;
|
||||
ssh_string ecdh_server_pubkey;
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
size_t digest_len; /* len of all the fields below */
|
||||
unsigned char *session_id;
|
||||
unsigned char *encryptIV;
|
||||
unsigned char *decryptIV;
|
||||
unsigned char *decryptkey;
|
||||
unsigned char *encryptkey;
|
||||
unsigned char *encryptMAC;
|
||||
unsigned char *decryptMAC;
|
||||
unsigned char hmacbuf[EVP_MAX_MD_SIZE];
|
||||
struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||
ssh_string server_pubkey;
|
||||
@ -62,6 +75,8 @@ struct ssh_crypto_struct {
|
||||
int delayed_compress_out;
|
||||
void *compress_out_ctx; /* don't touch it */
|
||||
void *compress_in_ctx; /* really, don't */
|
||||
enum ssh_key_exchange_e kex_type;
|
||||
enum ssh_mac_e mac_type; /* Mac operations to use for key gen */
|
||||
};
|
||||
|
||||
struct crypto_struct {
|
||||
|
@ -41,6 +41,9 @@ int dh_import_f(ssh_session session,ssh_string f_string);
|
||||
int dh_import_e(ssh_session session, ssh_string e_string);
|
||||
void dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
|
||||
int dh_build_k(ssh_session session);
|
||||
int ssh_client_dh_init(ssh_session session);
|
||||
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
int make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
|
39
include/libssh/ecdh.h
Normal file
39
include/libssh/ecdh.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2011 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef ECDH_H_
|
||||
#define ECDH_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
|
||||
#define HAVE_ECDH
|
||||
|
||||
#endif /* HAVE_OPENSSL_ECDH_H */
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
int ssh_client_ecdh_init(ssh_session session);
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
|
||||
#endif /* ECDH_H_ */
|
@ -32,6 +32,7 @@
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
typedef SHA_CTX* SHACTX;
|
||||
typedef SHA256_CTX* SHA256CTX;
|
||||
typedef MD5_CTX* MD5CTX;
|
||||
typedef HMAC_CTX* HMACCTX;
|
||||
|
||||
@ -67,6 +68,10 @@ typedef BN_CTX* bignum_CTX;
|
||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||
|
||||
SHA256CTX sha256_init(void);
|
||||
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
|
||||
void sha256_final(unsigned char *md, SHA256CTX c);
|
||||
|
||||
struct crypto_struct *ssh_get_ciphertab(void);
|
||||
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
@ -30,8 +30,13 @@
|
||||
typedef gcry_md_hd_t SHACTX;
|
||||
typedef gcry_md_hd_t MD5CTX;
|
||||
typedef gcry_md_hd_t HMACCTX;
|
||||
#define SHA_DIGEST_LEN 20
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LEN 16
|
||||
#define SHA256_DIGEST_LENGTH 32
|
||||
#define SHA384_DIGEST_LENGTH 48
|
||||
#define SHA512_DIGEST_LENGTH 64
|
||||
|
||||
#define EVP_MAX_MD_SIZE 36
|
||||
|
||||
typedef gcry_mpi_t bignum;
|
||||
|
@ -103,7 +103,7 @@ struct ssh_session_struct {
|
||||
enum ssh_auth_service_state_e auth_service_state;
|
||||
enum ssh_auth_state_e auth_state;
|
||||
enum ssh_channel_request_state_e global_req_state;
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
|
||||
KEX server_kex;
|
||||
KEX client_kex;
|
||||
ssh_buffer in_hashbuf;
|
||||
|
@ -13,6 +13,10 @@
|
||||
|
||||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
#define SSH2_MSG_KEX_ECDH_INIT 30
|
||||
#define SSH2_MSG_KEX_ECDH_REPLY 31
|
||||
#define SSH2_MSG_ECMQV_INIT 30
|
||||
#define SSH2_MSG_ECMQV_REPLY 31
|
||||
|
||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||
#define SSH2_MSG_KEX_DH_GEX_GROUP 31
|
||||
|
@ -25,7 +25,21 @@
|
||||
#include "config.h"
|
||||
#include "libssh/libcrypto.h"
|
||||
#include "libssh/libgcrypt.h"
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
enum ssh_mac_e {
|
||||
SSH_MAC_SHA1=1,
|
||||
SSH_MAC_SHA256,
|
||||
SSH_MAC_SHA384,
|
||||
SSH_MAC_SHA512
|
||||
};
|
||||
|
||||
enum ssh_hmac_e {
|
||||
SSH_HMAC_SHA1 = 1,
|
||||
SSH_HMAC_MD5
|
||||
};
|
||||
|
||||
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
|
||||
MD5CTX md5_init(void);
|
||||
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
||||
void md5_final(unsigned char *md,MD5CTX c);
|
||||
@ -33,9 +47,13 @@ SHACTX sha1_init(void);
|
||||
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
||||
void sha1_final(unsigned char *md,SHACTX c);
|
||||
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||
#define HMAC_SHA1 1
|
||||
#define HMAC_MD5 2
|
||||
HMACCTX hmac_init(const void *key,int len,int type);
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx);
|
||||
|
||||
HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type);
|
||||
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||
|
||||
|
@ -85,6 +85,7 @@ set(libssh_SRCS
|
||||
crc32.c
|
||||
crypt.c
|
||||
dh.c
|
||||
ecdh.c
|
||||
error.c
|
||||
getpass.c
|
||||
gzip.c
|
||||
|
83
src/client.c
83
src/client.c
@ -36,6 +36,7 @@
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/threads.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
@ -176,12 +177,8 @@ end:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
|
||||
ssh_string f = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY");
|
||||
@ -191,48 +188,23 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
|
||||
session->session_state,session->dh_handshake_state);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pubkey = buffer_get_ssh_string(packet);
|
||||
if (pubkey == NULL){
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
switch(session->next_crypto->kex_type){
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc=ssh_client_dh_reply(session, packet);
|
||||
break;
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
rc = ssh_client_ecdh_reply(session, packet);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply");
|
||||
goto error;
|
||||
}
|
||||
dh_import_pubkey(session, pubkey);
|
||||
|
||||
f = buffer_get_ssh_string(packet);
|
||||
if (f == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No F number in packet");
|
||||
goto error;
|
||||
if(rc==SSH_OK) {
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
if (dh_import_f(session, f) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot import f number");
|
||||
goto error;
|
||||
}
|
||||
ssh_string_burn(f);
|
||||
ssh_string_free(f);
|
||||
f=NULL;
|
||||
signature = buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
}
|
||||
session->dh_server_signature = signature;
|
||||
signature=NULL; /* ownership changed */
|
||||
if (dh_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
packet_send(session);
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
@ -274,12 +246,12 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
|
||||
}
|
||||
|
||||
/* Verify the host's signature. FIXME do it sooner */
|
||||
signature = session->dh_server_signature;
|
||||
session->dh_server_signature = NULL;
|
||||
signature = session->next_crypto->dh_server_signature;
|
||||
session->next_crypto->dh_server_signature = NULL;
|
||||
if (signature_verify(session, signature)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_log(session,SSH_LOG_PROTOCOL,"Signature verified and valid");
|
||||
/* forget it for now ... */
|
||||
ssh_string_burn(signature);
|
||||
ssh_string_free(signature);
|
||||
@ -325,7 +297,20 @@ static int dh_handshake(ssh_session session) {
|
||||
|
||||
switch (session->dh_handshake_state) {
|
||||
case DH_STATE_INIT:
|
||||
rc = ssh_client_dh_init(session);
|
||||
switch(session->next_crypto->kex_type){
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc = ssh_client_dh_init(session);
|
||||
break;
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
rc = ssh_client_ecdh_init(session);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rc=SSH_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
|
||||
#endif
|
||||
|
||||
if (session->version == 2) {
|
||||
ctx = hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1);
|
||||
ctx = hmac_init(session->current_crypto->encryptMAC,20,SSH_HMAC_SHA1);
|
||||
if (ctx == NULL) {
|
||||
SAFE_FREE(out);
|
||||
return NULL;
|
||||
@ -190,7 +190,7 @@ int packet_hmac_verify(ssh_session session, ssh_buffer buffer,
|
||||
unsigned int len;
|
||||
uint32_t seq;
|
||||
|
||||
ctx = hmac_init(session->current_crypto->decryptMAC, 20, HMAC_SHA1);
|
||||
ctx = hmac_init(session->current_crypto->decryptMAC, 20, SSH_HMAC_SHA1);
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
255
src/dh.c
255
src/dh.c
@ -521,6 +521,56 @@ int ssh_client_dh_init(ssh_session session){
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string f = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
pubkey = buffer_get_ssh_string(packet);
|
||||
if (pubkey == NULL){
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
dh_import_pubkey(session, pubkey);
|
||||
|
||||
f = buffer_get_ssh_string(packet);
|
||||
if (f == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No F number in packet");
|
||||
goto error;
|
||||
}
|
||||
if (dh_import_f(session, f) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot import f number");
|
||||
goto error;
|
||||
}
|
||||
ssh_string_burn(f);
|
||||
ssh_string_free(f);
|
||||
f=NULL;
|
||||
signature = buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_server_signature = signature;
|
||||
signature=NULL; /* ownership changed */
|
||||
if (dh_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc=packet_send(session);
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
return rc;
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static void sha_add(ssh_string str,SHACTX ctx){
|
||||
sha1_update(ctx,str,string_len(str)+4);
|
||||
@ -531,7 +581,6 @@ static void sha_add(ssh_string str,SHACTX ctx){
|
||||
*/
|
||||
|
||||
int make_sessionid(ssh_session session) {
|
||||
SHACTX ctx;
|
||||
ssh_string num = NULL;
|
||||
ssh_string str = NULL;
|
||||
ssh_buffer server_hash = NULL;
|
||||
@ -542,11 +591,6 @@ int make_sessionid(ssh_session session) {
|
||||
|
||||
enter_function();
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf = ssh_buffer_new();
|
||||
if (buf == NULL) {
|
||||
return rc;
|
||||
@ -614,29 +658,33 @@ int make_sessionid(ssh_session session) {
|
||||
if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if(session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1){
|
||||
num = make_bignum_string(session->next_crypto->e);
|
||||
if (num == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
num = make_bignum_string(session->next_crypto->e);
|
||||
if (num == NULL) {
|
||||
goto error;
|
||||
len = ssh_string_len(num) + 4;
|
||||
if (buffer_add_data(buf, num, len) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(num);
|
||||
num = make_bignum_string(session->next_crypto->f);
|
||||
if (num == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
len = ssh_string_len(num) + 4;
|
||||
if (buffer_add_data(buf, num, len) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(num);
|
||||
} else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256){
|
||||
buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey);
|
||||
buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey);
|
||||
}
|
||||
|
||||
len = ssh_string_len(num) + 4;
|
||||
if (buffer_add_data(buf, num, len) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(num);
|
||||
num = make_bignum_string(session->next_crypto->f);
|
||||
if (num == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
len = ssh_string_len(num) + 4;
|
||||
if (buffer_add_data(buf, num, len) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_free(num);
|
||||
num = make_bignum_string(session->next_crypto->k);
|
||||
if (num == NULL) {
|
||||
goto error;
|
||||
@ -651,8 +699,31 @@ int make_sessionid(ssh_session session) {
|
||||
ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
|
||||
#endif
|
||||
|
||||
sha1_update(ctx, buffer_get_rest(buf), buffer_get_rest_len(buf));
|
||||
sha1_final(session->next_crypto->session_id, ctx);
|
||||
switch(session->next_crypto->kex_type){
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA1;
|
||||
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||
if(session->next_crypto->session_id == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||
session->next_crypto->session_id);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA256;
|
||||
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||
if(session->next_crypto->session_id == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||
session->next_crypto->session_id);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
printf("Session hash: ");
|
||||
@ -723,126 +794,134 @@ int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
|
||||
}
|
||||
|
||||
static int generate_one_key(ssh_string k,
|
||||
unsigned char session_id[SHA_DIGEST_LEN],
|
||||
unsigned char output[SHA_DIGEST_LEN],
|
||||
char letter) {
|
||||
SHACTX ctx = NULL;
|
||||
struct ssh_crypto_struct *crypto, unsigned char *output, char letter) {
|
||||
ssh_mac_ctx ctx;
|
||||
ctx=ssh_mac_ctx_init(crypto->mac_type);
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sha1_update(ctx, k, ssh_string_len(k) + 4);
|
||||
sha1_update(ctx, session_id, SHA_DIGEST_LEN);
|
||||
sha1_update(ctx, &letter, 1);
|
||||
sha1_update(ctx, session_id, SHA_DIGEST_LEN);
|
||||
sha1_final(output, ctx);
|
||||
ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
|
||||
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||
ssh_mac_update(ctx, &letter, 1);
|
||||
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||
ssh_mac_final(output, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_session_keys(ssh_session session) {
|
||||
ssh_string k_string = NULL;
|
||||
SHACTX ctx = NULL;
|
||||
ssh_mac_ctx ctx = NULL;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
int rc = -1;
|
||||
|
||||
enter_function();
|
||||
|
||||
k_string = make_bignum_string(session->next_crypto->k);
|
||||
k_string = make_bignum_string(crypto->k);
|
||||
if (k_string == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
crypto->encryptIV = malloc(crypto->digest_len);
|
||||
crypto->decryptIV = malloc(crypto->digest_len);
|
||||
crypto->encryptkey = malloc(crypto->digest_len);
|
||||
crypto->decryptkey = malloc(crypto->digest_len);
|
||||
crypto->encryptMAC = malloc(crypto->digest_len);
|
||||
crypto->decryptMAC = malloc(crypto->digest_len);
|
||||
if(crypto->encryptIV == NULL || crypto->decryptIV == NULL ||
|
||||
crypto->encryptkey == NULL || crypto->decryptkey == NULL ||
|
||||
crypto->encryptMAC == NULL || crypto->decryptMAC == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* IV */
|
||||
if (session->client) {
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->encryptIV, 'A') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->encryptIV, 'A') < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->decryptIV, 'B') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->decryptIV, 'B') < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->decryptIV, 'A') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->decryptIV, 'A') < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->encryptIV, 'B') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->encryptIV, 'B') < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (session->client) {
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->encryptkey, 'C') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->encryptkey, 'C') < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->decryptkey, 'D') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->decryptkey, 'D') < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->decryptkey, 'C') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->decryptkey, 'C') < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->encryptkey, 'D') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->encryptkey, 'D') < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* some ciphers need more than 20 bytes of input key */
|
||||
/* XXX verify it's ok for server implementation */
|
||||
if (session->next_crypto->out_cipher->keysize > SHA_DIGEST_LEN * 8) {
|
||||
ctx = sha1_init();
|
||||
/* some ciphers need more than DIGEST_LEN bytes of input key */
|
||||
if (crypto->out_cipher->keysize > crypto->digest_len * 8) {
|
||||
crypto->encryptkey = realloc(crypto->encryptkey, crypto->digest_len * 2);
|
||||
if(crypto->encryptkey == NULL)
|
||||
goto error;
|
||||
ctx = ssh_mac_ctx_init(crypto->mac_type);
|
||||
if (ctx == NULL) {
|
||||
goto error;
|
||||
}
|
||||
sha1_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
||||
sha1_update(ctx, session->next_crypto->session_id, SHA_DIGEST_LEN);
|
||||
sha1_update(ctx, session->next_crypto->encryptkey, SHA_DIGEST_LEN);
|
||||
sha1_final(session->next_crypto->encryptkey + SHA_DIGEST_LEN, ctx);
|
||||
ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
||||
ssh_mac_update(ctx, crypto->session_id,
|
||||
crypto->digest_len);
|
||||
ssh_mac_update(ctx, crypto->encryptkey, crypto->digest_len);
|
||||
ssh_mac_final(crypto->encryptkey + crypto->digest_len, ctx);
|
||||
}
|
||||
|
||||
if (session->next_crypto->in_cipher->keysize > SHA_DIGEST_LEN * 8) {
|
||||
ctx = sha1_init();
|
||||
sha1_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
||||
sha1_update(ctx, session->next_crypto->session_id, SHA_DIGEST_LEN);
|
||||
sha1_update(ctx, session->next_crypto->decryptkey, SHA_DIGEST_LEN);
|
||||
sha1_final(session->next_crypto->decryptkey + SHA_DIGEST_LEN, ctx);
|
||||
if (crypto->in_cipher->keysize > crypto->digest_len * 8) {
|
||||
crypto->decryptkey = realloc(crypto->decryptkey, crypto->digest_len *2);
|
||||
if(crypto->decryptkey == NULL)
|
||||
goto error;
|
||||
ctx = ssh_mac_ctx_init(crypto->mac_type);
|
||||
ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4);
|
||||
ssh_mac_update(ctx, crypto->session_id,
|
||||
crypto->digest_len);
|
||||
ssh_mac_update(ctx, crypto->decryptkey, crypto->digest_len);
|
||||
ssh_mac_final(crypto->decryptkey + crypto->digest_len, ctx);
|
||||
}
|
||||
if(session->client) {
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->encryptMAC, 'E') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->encryptMAC, 'E') < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->decryptMAC, 'F') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->decryptMAC, 'F') < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->decryptMAC, 'E') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->decryptMAC, 'E') < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (generate_one_key(k_string, session->next_crypto->session_id,
|
||||
session->next_crypto->encryptMAC, 'F') < 0) {
|
||||
if (generate_one_key(k_string, crypto, crypto->encryptMAC, 'F') < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Encrypt IV", session->next_crypto->encryptIV, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Decrypt IV", session->next_crypto->decryptIV, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Encryption key", session->next_crypto->encryptkey,
|
||||
session->next_crypto->out_cipher->keysize);
|
||||
ssh_print_hexa("Decryption key", session->next_crypto->decryptkey,
|
||||
session->next_crypto->in_cipher->keysize);
|
||||
ssh_print_hexa("Encryption MAC", session->next_crypto->encryptMAC, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Decryption MAC", session->next_crypto->decryptMAC, 20);
|
||||
ssh_print_hexa("Encrypt IV", crypto->encryptIV, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Decrypt IV", crypto->decryptIV, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Encryption key", crypto->encryptkey,
|
||||
crypto->out_cipher->keysize);
|
||||
ssh_print_hexa("Decryption key", crypto->decryptkey,
|
||||
crypto->in_cipher->keysize);
|
||||
ssh_print_hexa("Encryption MAC", crypto->encryptMAC, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Decryption MAC", crypto->decryptMAC, 20);
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
@ -1090,7 +1169,7 @@ int signature_verify(ssh_session session, ssh_string signature) {
|
||||
"Going to verify a %s type signature", pubkey->type_c);
|
||||
|
||||
err = sig_verify(session,pubkey,sign,
|
||||
session->next_crypto->session_id,SHA_DIGEST_LEN);
|
||||
session->next_crypto->session_id, session->next_crypto->digest_len);
|
||||
signature_free(sign);
|
||||
session->next_crypto->server_pubkey_type = pubkey->type_c;
|
||||
publickey_free(pubkey);
|
||||
|
167
src/ecdh.c
Normal file
167
src/ecdh.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2011 by Aris Adamantiadis
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/ssh2.h"
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
#include <openssl/ecdh.h>
|
||||
|
||||
#define NISTP256 NID_X9_62_prime256v1
|
||||
#define NISTP384 NID_secp384r1
|
||||
#define NISTP521 NID_secp521r1
|
||||
|
||||
/** @internal
|
||||
* @brief Starts ecdh-sha2-nistp256 key exchange
|
||||
*/
|
||||
int ssh_client_ecdh_init(ssh_session session){
|
||||
ssh_string e = NULL;
|
||||
EC_KEY *key=NULL;
|
||||
const EC_GROUP *group;
|
||||
const EC_POINT *pubkey;
|
||||
ssh_string client_pubkey;
|
||||
int len;
|
||||
int rc;
|
||||
bignum_CTX ctx=BN_CTX_new();
|
||||
enter_function();
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT) < 0) {
|
||||
goto error;
|
||||
}
|
||||
key = EC_KEY_new_by_curve_name(NISTP256);
|
||||
group = EC_KEY_get0_group(key);
|
||||
EC_KEY_generate_key(key);
|
||||
pubkey=EC_KEY_get0_public_key(key);
|
||||
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||
NULL,0,ctx);
|
||||
client_pubkey=ssh_string_new(len);
|
||||
|
||||
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
|
||||
ssh_string_data(client_pubkey),len,ctx);
|
||||
buffer_add_ssh_string(session->out_buffer,client_pubkey);
|
||||
BN_CTX_free(ctx);
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
rc = packet_send(session);
|
||||
return rc;
|
||||
error:
|
||||
if(e != NULL){
|
||||
ssh_string_burn(e);
|
||||
ssh_string_free(e);
|
||||
}
|
||||
|
||||
leave_function();
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static void ecdh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
|
||||
session->next_crypto->server_pubkey = pubkey_string;
|
||||
}
|
||||
|
||||
static int ecdh_build_k(ssh_session session) {
|
||||
const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey);
|
||||
EC_POINT *pubkey=EC_POINT_new(group);
|
||||
void *buffer;
|
||||
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
session->next_crypto->k = bignum_new();
|
||||
if (session->next_crypto->k == NULL) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_ctx_free(ctx);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
EC_POINT_oct2point(group,pubkey,ssh_string_data(session->next_crypto->ecdh_server_pubkey),
|
||||
ssh_string_len(session->next_crypto->ecdh_server_pubkey),ctx);
|
||||
buffer = malloc(len);
|
||||
ECDH_compute_key(buffer,len,pubkey,session->next_crypto->ecdh_privkey,NULL);
|
||||
BN_bin2bn(buffer,len,session->next_crypto->k);
|
||||
free(buffer);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie", session->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie", session->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_ctx_free(ctx);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||
* a SSH_MSG_NEWKEYS
|
||||
*/
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
pubkey = buffer_get_ssh_string(packet);
|
||||
if (pubkey == NULL){
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
ecdh_import_pubkey(session, pubkey);
|
||||
|
||||
q_s_string = buffer_get_ssh_string(packet);
|
||||
if (q_s_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->ecdh_server_pubkey = q_s_string;
|
||||
signature = buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_server_signature = signature;
|
||||
signature=NULL; /* ownership changed */
|
||||
if (ecdh_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc=packet_send(session);
|
||||
ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
return rc;
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#endif /* HAVE_ECDH */
|
18
src/kex.c
18
src/kex.c
@ -42,6 +42,7 @@
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/kex.h"
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/ecdh.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#define BLOWFISH "blowfish-cbc,"
|
||||
@ -72,8 +73,14 @@
|
||||
#define ZLIB "none"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
#define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group1-sha1"
|
||||
#else
|
||||
#define KEY_EXCHANGE "diffie-hellman-group1-sha1"
|
||||
#endif
|
||||
|
||||
const char *default_methods[] = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
KEY_EXCHANGE,
|
||||
"ssh-rsa,ssh-dss",
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
@ -87,7 +94,7 @@ const char *default_methods[] = {
|
||||
};
|
||||
|
||||
const char *supported_methods[] = {
|
||||
"diffie-hellman-group1-sha1",
|
||||
KEY_EXCHANGE,
|
||||
"ssh-rsa,ssh-dss",
|
||||
AES BLOWFISH DES,
|
||||
AES BLOWFISH DES,
|
||||
@ -370,7 +377,7 @@ int set_kex(ssh_session session){
|
||||
ssh_get_random(client->cookie,16,0);
|
||||
client->methods=malloc(10 * sizeof(char **));
|
||||
if (client->methods == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No space left");
|
||||
ssh_set_error_oom(session);
|
||||
leave_function();
|
||||
return -1;
|
||||
}
|
||||
@ -394,6 +401,11 @@ int set_kex(ssh_session session){
|
||||
}
|
||||
}
|
||||
}
|
||||
if(strcmp(client->methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
|
||||
} else if(strcmp(client->methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
|
||||
}
|
||||
leave_function();
|
||||
return 0;
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ static int match_hashed_host(ssh_session session, const char *host,
|
||||
return 0;
|
||||
}
|
||||
|
||||
mac = hmac_init(buffer_get_rest(salt), buffer_get_rest_len(salt), HMAC_SHA1);
|
||||
mac = hmac_init(buffer_get_rest(salt), buffer_get_rest_len(salt), SSH_HMAC_SHA1);
|
||||
if (mac == NULL) {
|
||||
ssh_buffer_free(salt);
|
||||
ssh_buffer_free(hash);
|
||||
|
@ -57,6 +57,14 @@
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
union {
|
||||
SHACTX sha1_ctx;
|
||||
SHA256CTX sha256_ctx;
|
||||
} ctx;
|
||||
};
|
||||
|
||||
static int alloc_key(struct crypto_struct *cipher) {
|
||||
cipher->key = malloc(cipher->keylen);
|
||||
if (cipher->key == NULL) {
|
||||
@ -89,6 +97,29 @@ void sha1(unsigned char *digest, int len, unsigned char *hash) {
|
||||
SHA1(digest, len, hash);
|
||||
}
|
||||
|
||||
SHA256CTX sha256_init(void){
|
||||
SHA256CTX c = malloc(sizeof(*c));
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
SHA256_Init(c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void sha256_update(SHA256CTX c, const void *data, unsigned long len){
|
||||
SHA256_Update(c,data,len);
|
||||
}
|
||||
|
||||
void sha256_final(unsigned char *md, SHA256CTX c) {
|
||||
SHA256_Final(md, c);
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash) {
|
||||
SHA256(digest, len, hash);
|
||||
}
|
||||
|
||||
MD5CTX md5_init(void) {
|
||||
MD5CTX c = malloc(sizeof(*c));
|
||||
if (c == NULL) {
|
||||
@ -109,7 +140,56 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, int type) {
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
ctx->ctx.sha1_ctx = sha1_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA256:
|
||||
ctx->ctx.sha256_ctx = sha256_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA384:
|
||||
case SSH_MAC_SHA512:
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
sha1_update(ctx->ctx.sha1_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
sha256_update(ctx->ctx.sha256_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
case SSH_MAC_SHA512:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
sha1_final(md,ctx->ctx.sha1_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
sha256_final(md,ctx->ctx.sha256_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
case SSH_MAC_SHA512:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
HMACCTX ctx = NULL;
|
||||
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
@ -122,10 +202,10 @@ HMACCTX hmac_init(const void *key, int len, int type) {
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
case HMAC_SHA1:
|
||||
case SSH_HMAC_SHA1:
|
||||
HMAC_Init(ctx, key, len, EVP_sha1());
|
||||
break;
|
||||
case HMAC_MD5:
|
||||
case SSH_HMAC_MD5:
|
||||
HMAC_Init(ctx, key, len, EVP_md5());
|
||||
break;
|
||||
default:
|
||||
|
@ -31,6 +31,10 @@
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
gcry_md_hd_t ctx;
|
||||
};
|
||||
|
||||
static int alloc_key(struct crypto_struct *cipher) {
|
||||
cipher->key = malloc(cipher->keylen);
|
||||
@ -62,6 +66,10 @@ void sha1(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
|
||||
}
|
||||
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash){
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len);
|
||||
}
|
||||
|
||||
MD5CTX md5_init(void) {
|
||||
MD5CTX c = NULL;
|
||||
gcry_md_open(&c, GCRY_MD_MD5, 0);
|
||||
@ -79,14 +87,63 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, int type) {
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA1, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA256, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA384, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA512, 0);
|
||||
break;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||
gcry_md_write(ctx->ctx,data,len);
|
||||
}
|
||||
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
size_t len;
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
len=SHA_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
len=SHA256_DIGEST_LENGTH;
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
len=SHA384_DIGEST_LENGTH;
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
len=SHA512_DIGEST_LENGTH;
|
||||
break;
|
||||
}
|
||||
gcry_md_final(ctx->ctx);
|
||||
memcpy(md, gcry_md_read(ctx->ctx, 0), len);
|
||||
gcry_md_close(ctx->ctx);
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
HMACCTX c = NULL;
|
||||
|
||||
switch(type) {
|
||||
case HMAC_SHA1:
|
||||
case SSH_HMAC_SHA1:
|
||||
gcry_md_open(&c, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
|
||||
break;
|
||||
case HMAC_MD5:
|
||||
case SSH_HMAC_MD5:
|
||||
gcry_md_open(&c, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
|
||||
break;
|
||||
default:
|
||||
|
Loading…
x
Reference in New Issue
Block a user