Blame src/libgcrypt.c

Packit 6c0a39
/*
Packit 6c0a39
 * This file is part of the SSH Library
Packit 6c0a39
 *
Packit 6c0a39
 * Copyright (c) 2009 by Aris Adamantiadis
Packit 6c0a39
 * Copyright (C) 2016 g10 Code GmbH
Packit 6c0a39
 *
Packit 6c0a39
 * The SSH Library is free software; you can redistribute it and/or modify
Packit 6c0a39
 * it under the terms of the GNU Lesser General Public License as published by
Packit 6c0a39
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit 6c0a39
 * option) any later version.
Packit 6c0a39
 *
Packit 6c0a39
 * The SSH Library is distributed in the hope that it will be useful, but
Packit 6c0a39
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 6c0a39
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit 6c0a39
 * License for more details.
Packit 6c0a39
 *
Packit 6c0a39
 * You should have received a copy of the GNU Lesser General Public License
Packit 6c0a39
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit 6c0a39
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit 6c0a39
 * MA 02111-1307, USA.
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
#include "config.h"
Packit 6c0a39
Packit 6c0a39
#include <stdlib.h>
Packit 6c0a39
#include <stdio.h>
Packit 6c0a39
#include <string.h>
Packit 6c0a39
Packit 6c0a39
#include "libssh/priv.h"
Packit 6c0a39
#include "libssh/session.h"
Packit 6c0a39
#include "libssh/crypto.h"
Packit 6c0a39
#include "libssh/wrapper.h"
Packit 6c0a39
#include "libssh/string.h"
Packit 6c0a39
#include "libssh/misc.h"
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_LIBGCRYPT
Packit 6c0a39
#include <gcrypt.h>
Packit 6c0a39
Packit 6c0a39
static int libgcrypt_initialized = 0;
Packit 6c0a39
Packit 6c0a39
static int alloc_key(struct ssh_cipher_struct *cipher) {
Packit 6c0a39
    cipher->key = malloc(cipher->keylen);
Packit 6c0a39
    if (cipher->key == NULL) {
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void ssh_reseed(void){
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
int ssh_get_random(void *where, int len, int strong)
Packit 6c0a39
{
Packit 6c0a39
    /* variable not used in gcrypt */
Packit 6c0a39
    (void) strong;
Packit 6c0a39
Packit 6c0a39
    /* not using GCRY_VERY_STRONG_RANDOM which is a bit overkill */
Packit 6c0a39
    gcry_randomize(where,len,GCRY_STRONG_RANDOM);
Packit 6c0a39
Packit 6c0a39
    return 1;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
SHACTX sha1_init(void) {
Packit 6c0a39
  SHACTX ctx = NULL;
Packit 6c0a39
  gcry_md_open(&ctx, GCRY_MD_SHA1, 0);
Packit 6c0a39
Packit 6c0a39
  return ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha1_update(SHACTX c, const void *data, unsigned long len) {
Packit 6c0a39
  gcry_md_write(c, data, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha1_final(unsigned char *md, SHACTX c) {
Packit 6c0a39
  gcry_md_final(c);
Packit 6c0a39
  memcpy(md, gcry_md_read(c, 0), SHA_DIGEST_LEN);
Packit 6c0a39
  gcry_md_close(c);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha1(const unsigned char *digest, int len, unsigned char *hash) {
Packit 6c0a39
  gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_GCRYPT_ECC
Packit 6c0a39
static int nid_to_md_algo(int nid)
Packit 6c0a39
{
Packit 6c0a39
    switch (nid) {
Packit 6c0a39
    case NID_gcrypt_nistp256:
Packit 6c0a39
        return GCRY_MD_SHA256;
Packit 6c0a39
    case NID_gcrypt_nistp384:
Packit 6c0a39
        return GCRY_MD_SHA384;
Packit 6c0a39
    case NID_gcrypt_nistp521:
Packit 6c0a39
        return GCRY_MD_SHA512;
Packit 6c0a39
    }
Packit 6c0a39
    return GCRY_MD_NONE;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void evp(int nid, unsigned char *digest, int len,
Packit 6c0a39
         unsigned char *hash, unsigned int *hlen)
Packit 6c0a39
{
Packit 6c0a39
    int algo = nid_to_md_algo(nid);
Packit 6c0a39
Packit 6c0a39
    /* Note: What gcrypt calls 'hash' is called 'digest' here and
Packit 6c0a39
       vice-versa.  */
Packit 6c0a39
    gcry_md_hash_buffer(algo, hash, digest, len);
Packit 6c0a39
    *hlen = gcry_md_get_algo_dlen(algo);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
EVPCTX evp_init(int nid)
Packit 6c0a39
{
Packit 6c0a39
    gcry_error_t err;
Packit 6c0a39
    int algo = nid_to_md_algo(nid);
Packit 6c0a39
    EVPCTX ctx;
Packit 6c0a39
Packit 6c0a39
    err = gcry_md_open(&ctx, algo, 0);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        return NULL;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
Packit 6c0a39
{
Packit 6c0a39
    gcry_md_write(ctx, data, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
Packit 6c0a39
{
Packit 6c0a39
    int algo = gcry_md_get_algo(ctx);
Packit 6c0a39
    *mdlen = gcry_md_get_algo_dlen(algo);
Packit 6c0a39
    memcpy(md, gcry_md_read(ctx, algo), *mdlen);
Packit 6c0a39
    gcry_md_close(ctx);
Packit 6c0a39
}
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
SHA256CTX sha256_init(void) {
Packit 6c0a39
  SHA256CTX ctx = NULL;
Packit 6c0a39
  gcry_md_open(&ctx, GCRY_MD_SHA256, 0);
Packit 6c0a39
Packit 6c0a39
  return ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha256_update(SHACTX c, const void *data, unsigned long len) {
Packit 6c0a39
  gcry_md_write(c, data, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha256_final(unsigned char *md, SHACTX c) {
Packit 6c0a39
  gcry_md_final(c);
Packit 6c0a39
  memcpy(md, gcry_md_read(c, 0), SHA256_DIGEST_LEN);
Packit 6c0a39
  gcry_md_close(c);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha256(const unsigned char *digest, int len, unsigned char *hash){
Packit 6c0a39
  gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
SHA384CTX sha384_init(void) {
Packit 6c0a39
  SHA384CTX ctx = NULL;
Packit 6c0a39
  gcry_md_open(&ctx, GCRY_MD_SHA384, 0);
Packit 6c0a39
Packit 6c0a39
  return ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha384_update(SHACTX c, const void *data, unsigned long len) {
Packit 6c0a39
  gcry_md_write(c, data, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha384_final(unsigned char *md, SHACTX c) {
Packit 6c0a39
  gcry_md_final(c);
Packit 6c0a39
  memcpy(md, gcry_md_read(c, 0), SHA384_DIGEST_LEN);
Packit 6c0a39
  gcry_md_close(c);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha384(const unsigned char *digest, int len, unsigned char *hash) {
Packit 6c0a39
  gcry_md_hash_buffer(GCRY_MD_SHA384, hash, digest, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
SHA512CTX sha512_init(void) {
Packit 6c0a39
  SHA512CTX ctx = NULL;
Packit 6c0a39
  gcry_md_open(&ctx, GCRY_MD_SHA512, 0);
Packit 6c0a39
Packit 6c0a39
  return ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha512_update(SHACTX c, const void *data, unsigned long len) {
Packit 6c0a39
  gcry_md_write(c, data, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha512_final(unsigned char *md, SHACTX c) {
Packit 6c0a39
  gcry_md_final(c);
Packit 6c0a39
  memcpy(md, gcry_md_read(c, 0), SHA512_DIGEST_LEN);
Packit 6c0a39
  gcry_md_close(c);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void sha512(const unsigned char *digest, int len, unsigned char *hash) {
Packit 6c0a39
  gcry_md_hash_buffer(GCRY_MD_SHA512, hash, digest, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
MD5CTX md5_init(void) {
Packit 6c0a39
  MD5CTX c = NULL;
Packit 6c0a39
  gcry_md_open(&c, GCRY_MD_MD5, 0);
Packit 6c0a39
Packit 6c0a39
  return c;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void md5_update(MD5CTX c, const void *data, unsigned long len) {
Packit 6c0a39
    gcry_md_write(c,data,len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void md5_final(unsigned char *md, MD5CTX c) {
Packit 6c0a39
  gcry_md_final(c);
Packit 6c0a39
  memcpy(md, gcry_md_read(c, 0), MD5_DIGEST_LEN);
Packit 6c0a39
  gcry_md_close(c);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
int ssh_kdf(struct ssh_crypto_struct *crypto,
Packit 6c0a39
            unsigned char *key, size_t key_len,
Packit 6c0a39
            int key_type, unsigned char *output,
Packit 6c0a39
            size_t requested_len)
Packit 6c0a39
{
Packit 6c0a39
    return sshkdf_derive_key(crypto, key, key_len,
Packit 6c0a39
                             key_type, output, requested_len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
Packit 6c0a39
  HMACCTX c = NULL;
Packit 6c0a39
Packit 6c0a39
  switch(type) {
Packit 6c0a39
    case SSH_HMAC_SHA1:
Packit 6c0a39
      gcry_md_open(&c, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
Packit 6c0a39
      break;
Packit 6c0a39
    case SSH_HMAC_SHA256:
Packit 6c0a39
      gcry_md_open(&c, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
Packit 6c0a39
      break;
Packit 6c0a39
    case SSH_HMAC_SHA512:
Packit 6c0a39
      gcry_md_open(&c, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC);
Packit 6c0a39
      break;
Packit 6c0a39
    case SSH_HMAC_MD5:
Packit 6c0a39
      gcry_md_open(&c, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
Packit 6c0a39
      break;
Packit 6c0a39
    default:
Packit 6c0a39
      c = NULL;
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  gcry_md_setkey(c, key, len);
Packit 6c0a39
Packit 6c0a39
  return c;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void hmac_update(HMACCTX c, const void *data, unsigned long len) {
Packit 6c0a39
  gcry_md_write(c, data, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len) {
Packit 6c0a39
  *len = gcry_md_get_algo_dlen(gcry_md_get_algo(c));
Packit 6c0a39
  memcpy(hashmacbuf, gcry_md_read(c, 0), *len);
Packit 6c0a39
  gcry_md_close(c);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
#ifdef WITH_BLOWFISH_CIPHER
Packit 6c0a39
/* the wrapper functions for blowfish */
Packit 6c0a39
static int blowfish_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
Packit 6c0a39
  if (cipher->key == NULL) {
Packit 6c0a39
    if (alloc_key(cipher) < 0) {
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_BLOWFISH,
Packit 6c0a39
        GCRY_CIPHER_MODE_CBC, 0)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if (gcry_cipher_setkey(cipher->key[0], key, 16)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void blowfish_encrypt(struct ssh_cipher_struct *cipher, void *in,
Packit 6c0a39
    void *out, unsigned long len) {
Packit 6c0a39
  gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void blowfish_decrypt(struct ssh_cipher_struct *cipher, void *in,
Packit 6c0a39
    void *out, unsigned long len) {
Packit 6c0a39
  gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
Packit 6c0a39
}
Packit 6c0a39
#endif /* WITH_BLOWFISH_CIPHER */
Packit 6c0a39
Packit 6c0a39
static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
Packit 6c0a39
  int mode=GCRY_CIPHER_MODE_CBC;
Packit 6c0a39
  if (cipher->key == NULL) {
Packit 6c0a39
    if (alloc_key(cipher) < 0) {
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if(strstr(cipher->name,"-ctr"))
Packit 6c0a39
      mode=GCRY_CIPHER_MODE_CTR;
Packit 6c0a39
    if (strstr(cipher->name, "-gcm"))
Packit 6c0a39
      mode = GCRY_CIPHER_MODE_GCM;
Packit 6c0a39
    switch (cipher->keysize) {
Packit 6c0a39
      case 128:
Packit 6c0a39
        if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
Packit 6c0a39
              mode, 0)) {
Packit 6c0a39
          SAFE_FREE(cipher->key);
Packit 6c0a39
          return -1;
Packit 6c0a39
        }
Packit 6c0a39
        break;
Packit 6c0a39
      case 192:
Packit 6c0a39
        if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES192,
Packit 6c0a39
              mode, 0)) {
Packit 6c0a39
          SAFE_FREE(cipher->key);
Packit 6c0a39
          return -1;
Packit 6c0a39
        }
Packit 6c0a39
        break;
Packit 6c0a39
      case 256:
Packit 6c0a39
        if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES256,
Packit 6c0a39
              mode, 0)) {
Packit 6c0a39
          SAFE_FREE(cipher->key);
Packit 6c0a39
          return -1;
Packit 6c0a39
        }
Packit 6c0a39
        break;
Packit Service fcc0d2
      default:
Packit Service fcc0d2
        SSH_LOG(SSH_LOG_WARNING, "Unksupported key length %u.", cipher->keysize);
Packit Service fcc0d2
        SAFE_FREE(cipher->key);
Packit Service fcc0d2
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if (gcry_cipher_setkey(cipher->key[0], key, cipher->keysize / 8)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if(mode == GCRY_CIPHER_MODE_CBC){
Packit 6c0a39
      if (gcry_cipher_setiv(cipher->key[0], IV, 16)) {
Packit 6c0a39
Packit 6c0a39
        SAFE_FREE(cipher->key);
Packit 6c0a39
        return -1;
Packit 6c0a39
      }
Packit 6c0a39
    } else if (mode == GCRY_CIPHER_MODE_GCM) {
Packit 6c0a39
      /* Store the IV so we can handle the packet counter increments later
Packit 6c0a39
       * The IV is passed to the cipher context later.
Packit 6c0a39
       */
Packit 6c0a39
      memcpy(cipher->last_iv, IV, AES_GCM_IVLEN);
Packit 6c0a39
    } else {
Packit 6c0a39
      if(gcry_cipher_setctr(cipher->key[0],IV,16)){
Packit 6c0a39
        SAFE_FREE(cipher->key);
Packit 6c0a39
        return -1;
Packit 6c0a39
      }
Packit 6c0a39
    }
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void aes_encrypt(struct ssh_cipher_struct *cipher,
Packit 6c0a39
                        void *in,
Packit 6c0a39
                        void *out,
Packit 6c0a39
                        size_t len)
Packit 6c0a39
{
Packit 6c0a39
    gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void aes_decrypt(struct ssh_cipher_struct *cipher,
Packit 6c0a39
                        void *in,
Packit 6c0a39
                        void *out,
Packit 6c0a39
                        size_t len)
Packit 6c0a39
{
Packit 6c0a39
    gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int
Packit 6c0a39
aes_aead_get_length(struct ssh_cipher_struct *cipher,
Packit 6c0a39
                    void *in,
Packit 6c0a39
                    uint8_t *out,
Packit 6c0a39
                    size_t len,
Packit 6c0a39
                    uint64_t seq)
Packit 6c0a39
{
Packit 6c0a39
    (void)cipher;
Packit 6c0a39
    (void)seq;
Packit 6c0a39
Packit 6c0a39
    /* The length is not encrypted: Copy it to the result buffer */
Packit 6c0a39
    memcpy(out, in, len);
Packit 6c0a39
Packit 6c0a39
    return SSH_OK;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void
Packit 6c0a39
aes_gcm_encrypt(struct ssh_cipher_struct *cipher,
Packit 6c0a39
                void *in,
Packit 6c0a39
                void *out,
Packit 6c0a39
                size_t len,
Packit 6c0a39
                uint8_t *tag,
Packit 6c0a39
                uint64_t seq)
Packit 6c0a39
{
Packit 6c0a39
    gpg_error_t err;
Packit 6c0a39
    size_t aadlen, authlen;
Packit 6c0a39
Packit 6c0a39
    (void)seq;
Packit 6c0a39
Packit 6c0a39
    aadlen = cipher->lenfield_blocksize;
Packit 6c0a39
    authlen = cipher->tag_size;
Packit 6c0a39
Packit 6c0a39
    /* increment IV */
Packit 6c0a39
    err = gcry_cipher_setiv(cipher->key[0],
Packit 6c0a39
                            cipher->last_iv,
Packit 6c0a39
                            AES_GCM_IVLEN);
Packit 6c0a39
    /* This actualy does not increment the packet counter for the
Packit 6c0a39
     * current encryption operation, but for the next one. The first
Packit 6c0a39
     * operation needs to be completed with the derived IV.
Packit 6c0a39
     *
Packit 6c0a39
     * The IV buffer has the following structure:
Packit 6c0a39
     * [ 4B static IV ][ 8B packet counter ][ 4B block counter ]
Packit 6c0a39
     */
Packit 6c0a39
    uint64_inc(cipher->last_iv + 4);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_setiv failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    /* Pass the authenticated data (packet_length) */
Packit 6c0a39
    err = gcry_cipher_authenticate(cipher->key[0], in, aadlen);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_authenticate failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return;
Packit 6c0a39
    }
Packit 6c0a39
    memcpy(out, in, aadlen);
Packit 6c0a39
Packit 6c0a39
    /* Encrypt the rest of the data */
Packit 6c0a39
    err = gcry_cipher_encrypt(cipher->key[0],
Packit 6c0a39
                              (unsigned char *)out + aadlen,
Packit 6c0a39
                              len - aadlen,
Packit 6c0a39
                              (unsigned char *)in + aadlen,
Packit 6c0a39
                              len - aadlen);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_encrypt failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    /* Calculate the tag */
Packit 6c0a39
    err = gcry_cipher_gettag(cipher->key[0],
Packit 6c0a39
                             (void *)tag,
Packit 6c0a39
                             authlen);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_gettag failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return;
Packit 6c0a39
    }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int
Packit 6c0a39
aes_gcm_decrypt(struct ssh_cipher_struct *cipher,
Packit 6c0a39
                void *complete_packet,
Packit 6c0a39
                uint8_t *out,
Packit 6c0a39
                size_t encrypted_size,
Packit 6c0a39
                uint64_t seq)
Packit 6c0a39
{
Packit 6c0a39
    gpg_error_t err;
Packit 6c0a39
    size_t aadlen, authlen;
Packit 6c0a39
Packit 6c0a39
    (void)seq;
Packit 6c0a39
Packit 6c0a39
    aadlen = cipher->lenfield_blocksize;
Packit 6c0a39
    authlen = cipher->tag_size;
Packit 6c0a39
Packit 6c0a39
    /* increment IV */
Packit 6c0a39
    err = gcry_cipher_setiv(cipher->key[0],
Packit 6c0a39
                            cipher->last_iv,
Packit 6c0a39
                            AES_GCM_IVLEN);
Packit 6c0a39
    /* This actualy does not increment the packet counter for the
Packit 6c0a39
     * current encryption operation, but for the next one. The first
Packit 6c0a39
     * operation needs to be completed with the derived IV.
Packit 6c0a39
     *
Packit 6c0a39
     * The IV buffer has the following structure:
Packit 6c0a39
     * [ 4B static IV ][ 8B packet counter ][ 4B block counter ]
Packit 6c0a39
     */
Packit 6c0a39
    uint64_inc(cipher->last_iv + 4);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_setiv failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    /* Pass the authenticated data (packet_length) */
Packit 6c0a39
    err = gcry_cipher_authenticate(cipher->key[0],
Packit 6c0a39
                                   complete_packet,
Packit 6c0a39
                                   aadlen);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_authenticate failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    /* Do not copy the length to the target buffer, because it is already processed */
Packit 6c0a39
    //memcpy(out, complete_packet, aadlen);
Packit 6c0a39
Packit 6c0a39
    /* Encrypt the rest of the data */
Packit 6c0a39
    err = gcry_cipher_decrypt(cipher->key[0],
Packit 6c0a39
                              out,
Packit 6c0a39
                              encrypted_size,
Packit 6c0a39
                              (unsigned char *)complete_packet + aadlen,
Packit 6c0a39
                              encrypted_size);
Packit 6c0a39
    if (err) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_decrypt failed: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    /* Check the tag */
Packit 6c0a39
    err = gcry_cipher_checktag(cipher->key[0],
Packit 6c0a39
                               (unsigned char *)complete_packet + aadlen + encrypted_size,
Packit 6c0a39
                               authlen);
Packit 6c0a39
    if (gpg_err_code(err) == GPG_ERR_CHECKSUM) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "The authentication tag does not match");
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    } else if (err != GPG_ERR_NO_ERROR) {
Packit 6c0a39
        SSH_LOG(SSH_LOG_WARNING, "General error while decryption: %s",
Packit 6c0a39
                gpg_strerror(err));
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    return SSH_OK;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int des3_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
Packit 6c0a39
  if (cipher->key == NULL) {
Packit 6c0a39
    if (alloc_key(cipher) < 0) {
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_3DES,
Packit 6c0a39
          GCRY_CIPHER_MODE_CBC, 0)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if (gcry_cipher_setkey(cipher->key[0], key, 24)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
    if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
Packit 6c0a39
      SAFE_FREE(cipher->key);
Packit 6c0a39
      return -1;
Packit 6c0a39
    }
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void des3_encrypt(struct ssh_cipher_struct *cipher, void *in,
Packit 6c0a39
    void *out, unsigned long len) {
Packit 6c0a39
  gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static void des3_decrypt(struct ssh_cipher_struct *cipher, void *in,
Packit 6c0a39
    void *out, unsigned long len) {
Packit 6c0a39
  gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/* the table of supported ciphers */
Packit 6c0a39
static struct ssh_cipher_struct ssh_ciphertab[] = {
Packit 6c0a39
#ifdef WITH_BLOWFISH_CIPHER
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "blowfish-cbc",
Packit 6c0a39
    .blocksize       = 8,
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 128,
Packit 6c0a39
    .set_encrypt_key = blowfish_set_key,
Packit 6c0a39
    .set_decrypt_key = blowfish_set_key,
Packit 6c0a39
    .encrypt     = blowfish_encrypt,
Packit 6c0a39
    .decrypt     = blowfish_decrypt
Packit 6c0a39
  },
Packit 6c0a39
#endif /* WITH_BLOWFISH_CIPHER */
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "aes128-ctr",
Packit 6c0a39
    .blocksize       = 16,
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 128,
Packit 6c0a39
    .set_encrypt_key = aes_set_key,
Packit 6c0a39
    .set_decrypt_key = aes_set_key,
Packit 6c0a39
    .encrypt     = aes_encrypt,
Packit 6c0a39
    .decrypt     = aes_encrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
      .name            = "aes192-ctr",
Packit 6c0a39
      .blocksize       = 16,
Packit 6c0a39
      .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
      .key             = NULL,
Packit 6c0a39
      .keysize         = 192,
Packit 6c0a39
      .set_encrypt_key = aes_set_key,
Packit 6c0a39
      .set_decrypt_key = aes_set_key,
Packit 6c0a39
      .encrypt     = aes_encrypt,
Packit 6c0a39
      .decrypt     = aes_encrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
      .name            = "aes256-ctr",
Packit 6c0a39
      .blocksize       = 16,
Packit 6c0a39
      .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
      .key             = NULL,
Packit 6c0a39
      .keysize         = 256,
Packit 6c0a39
      .set_encrypt_key = aes_set_key,
Packit 6c0a39
      .set_decrypt_key = aes_set_key,
Packit 6c0a39
      .encrypt     = aes_encrypt,
Packit 6c0a39
      .decrypt     = aes_encrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "aes128-cbc",
Packit 6c0a39
    .blocksize       = 16,
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 128,
Packit 6c0a39
    .set_encrypt_key = aes_set_key,
Packit 6c0a39
    .set_decrypt_key = aes_set_key,
Packit 6c0a39
    .encrypt     = aes_encrypt,
Packit 6c0a39
    .decrypt     = aes_decrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "aes192-cbc",
Packit 6c0a39
    .blocksize       = 16,
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 192,
Packit 6c0a39
    .set_encrypt_key = aes_set_key,
Packit 6c0a39
    .set_decrypt_key = aes_set_key,
Packit 6c0a39
    .encrypt     = aes_encrypt,
Packit 6c0a39
    .decrypt     = aes_decrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "aes256-cbc",
Packit 6c0a39
    .blocksize       = 16,
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 256,
Packit 6c0a39
    .set_encrypt_key = aes_set_key,
Packit 6c0a39
    .set_decrypt_key = aes_set_key,
Packit 6c0a39
    .encrypt     = aes_encrypt,
Packit 6c0a39
    .decrypt     = aes_decrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "aes128-gcm@openssh.com",
Packit 6c0a39
    .blocksize       = 16,
Packit 6c0a39
    .lenfield_blocksize = 4, /* not encrypted, but authenticated */
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 128,
Packit 6c0a39
    .tag_size        = AES_GCM_TAGLEN,
Packit 6c0a39
    .set_encrypt_key = aes_set_key,
Packit 6c0a39
    .set_decrypt_key = aes_set_key,
Packit 6c0a39
    .aead_encrypt    = aes_gcm_encrypt,
Packit 6c0a39
    .aead_decrypt_length = aes_aead_get_length,
Packit 6c0a39
    .aead_decrypt    = aes_gcm_decrypt,
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "aes256-gcm@openssh.com",
Packit 6c0a39
    .blocksize       = 16,
Packit 6c0a39
    .lenfield_blocksize = 4, /* not encrypted, but authenticated */
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 256,
Packit 6c0a39
    .tag_size        = AES_GCM_TAGLEN,
Packit 6c0a39
    .set_encrypt_key = aes_set_key,
Packit 6c0a39
    .set_decrypt_key = aes_set_key,
Packit 6c0a39
    .aead_encrypt    = aes_gcm_encrypt,
Packit 6c0a39
    .aead_decrypt_length = aes_aead_get_length,
Packit 6c0a39
    .aead_decrypt    = aes_gcm_decrypt,
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = "3des-cbc",
Packit 6c0a39
    .blocksize       = 8,
Packit 6c0a39
    .keylen          = sizeof(gcry_cipher_hd_t),
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 192,
Packit 6c0a39
    .set_encrypt_key = des3_set_key,
Packit 6c0a39
    .set_decrypt_key = des3_set_key,
Packit 6c0a39
    .encrypt     = des3_encrypt,
Packit 6c0a39
    .decrypt     = des3_decrypt
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name = "chacha20-poly1305@openssh.com"
Packit 6c0a39
  },
Packit 6c0a39
  {
Packit 6c0a39
    .name            = NULL,
Packit 6c0a39
    .blocksize       = 0,
Packit 6c0a39
    .keylen          = 0,
Packit 6c0a39
    .key             = NULL,
Packit 6c0a39
    .keysize         = 0,
Packit 6c0a39
    .set_encrypt_key = NULL,
Packit 6c0a39
    .set_decrypt_key = NULL,
Packit 6c0a39
    .encrypt     = NULL,
Packit 6c0a39
    .decrypt     = NULL
Packit 6c0a39
  }
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
struct ssh_cipher_struct *ssh_get_ciphertab(void)
Packit 6c0a39
{
Packit 6c0a39
  return ssh_ciphertab;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/*
Packit 6c0a39
 * Extract an MPI from the given s-expression SEXP named NAME which is
Packit 6c0a39
 * encoded using INFORMAT and store it in a newly allocated ssh_string
Packit 6c0a39
 * encoded using OUTFORMAT.
Packit 6c0a39
 */
Packit 6c0a39
ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp,
Packit 6c0a39
                                const char *name,
Packit 6c0a39
                                enum gcry_mpi_format informat,
Packit 6c0a39
                                enum gcry_mpi_format outformat)
Packit 6c0a39
{
Packit 6c0a39
    gpg_error_t err;
Packit 6c0a39
    ssh_string result = NULL;
Packit 6c0a39
    gcry_sexp_t fragment = NULL;
Packit 6c0a39
    gcry_mpi_t mpi = NULL;
Packit 6c0a39
    size_t size;
Packit 6c0a39
Packit 6c0a39
    fragment = gcry_sexp_find_token(sexp, name, 0);
Packit 6c0a39
    if (fragment == NULL) {
Packit 6c0a39
        goto fail;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    mpi = gcry_sexp_nth_mpi(fragment, 1, informat);
Packit 6c0a39
    if (mpi == NULL) {
Packit 6c0a39
        goto fail;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    err = gcry_mpi_print(outformat, NULL, 0, &size, mpi);
Packit 6c0a39
    if (err != 0) {
Packit 6c0a39
        goto fail;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    result = ssh_string_new(size);
Packit 6c0a39
    if (result == NULL) {
Packit 6c0a39
        goto fail;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    err = gcry_mpi_print(outformat, ssh_string_data(result), size, NULL, mpi);
Packit 6c0a39
    if (err != 0) {
Packit 6c0a39
        ssh_string_burn(result);
Packit Service fcc0d2
        SSH_STRING_FREE(result);
Packit 6c0a39
        result = NULL;
Packit 6c0a39
        goto fail;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
fail:
Packit 6c0a39
    gcry_sexp_release(fragment);
Packit 6c0a39
    gcry_mpi_release(mpi);
Packit 6c0a39
    return result;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @internal
Packit 6c0a39
 *
Packit 6c0a39
 * @brief Initialize libgcrypt's subsystem
Packit 6c0a39
 */
Packit 6c0a39
int ssh_crypto_init(void)
Packit 6c0a39
{
Packit 6c0a39
    size_t i;
Packit 6c0a39
Packit 6c0a39
    if (libgcrypt_initialized) {
Packit 6c0a39
        return SSH_OK;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    gcry_check_version(NULL);
Packit 6c0a39
Packit 6c0a39
    /* While the secure memory is not set up */
Packit 6c0a39
    gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
Packit 6c0a39
Packit 6c0a39
    if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P, 0)) {
Packit 6c0a39
        gcry_control(GCRYCTL_INIT_SECMEM, 4096);
Packit 6c0a39
        gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    /* Re-enable warning */
Packit 6c0a39
    gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
Packit 6c0a39
Packit 6c0a39
    for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
Packit 6c0a39
        int cmp;
Packit 6c0a39
        cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@openssh.com");
Packit 6c0a39
        if (cmp == 0) {
Packit 6c0a39
            memcpy(&ssh_ciphertab[i],
Packit 6c0a39
                   ssh_get_chacha20poly1305_cipher(),
Packit 6c0a39
                   sizeof(struct ssh_cipher_struct));
Packit 6c0a39
            break;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    libgcrypt_initialized = 1;
Packit 6c0a39
Packit 6c0a39
    return SSH_OK;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @internal
Packit 6c0a39
 *
Packit 6c0a39
 * @brief Finalize libgcrypt's subsystem
Packit 6c0a39
 */
Packit 6c0a39
void ssh_crypto_finalize(void)
Packit 6c0a39
{
Packit 6c0a39
    if (!libgcrypt_initialized) {
Packit 6c0a39
        return;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    gcry_control(GCRYCTL_TERM_SECMEM);
Packit 6c0a39
Packit 6c0a39
    libgcrypt_initialized = 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
#endif