Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/s390/crypto/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 13 kB image not shown  

Quelle  des_s390.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Cryptographic API.
 *
 * s390 implementation of the DES Cipher Algorithm.
 *
 * Copyright IBM Corp. 2003, 2011
 * Author(s): Thomas Spatzier
 *       Jan Glauber (jan.glauber@de.ibm.com)
 */


#include <linux/init.h>
#include <linux/module.h>
#include <linux/cpufeature.h>
#include <linux/crypto.h>
#include <linux/fips.h>
#include <linux/mutex.h>
#include <crypto/algapi.h>
#include <crypto/internal/des.h>
#include <crypto/internal/skcipher.h>
#include <asm/cpacf.h>

#define DES3_KEY_SIZE (3 * DES_KEY_SIZE)

static u8 *ctrblk;
static DEFINE_MUTEX(ctrblk_lock);

static cpacf_mask_t km_functions, kmc_functions, kmctr_functions;

struct s390_des_ctx {
 u8 iv[DES_BLOCK_SIZE];
 u8 key[DES3_KEY_SIZE];
};

static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
        unsigned int key_len)
{
 struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
 int err;

 err = crypto_des_verify_key(tfm, key);
 if (err)
  return err;

 memcpy(ctx->key, key, key_len);
 return 0;
}

static int des_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
          unsigned int key_len)
{
 return des_setkey(crypto_skcipher_tfm(tfm), key, key_len);
}

static void s390_des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
 struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);

 cpacf_km(CPACF_KM_DEA, ctx->key, out, in, DES_BLOCK_SIZE);
}

static void s390_des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
 struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);

 cpacf_km(CPACF_KM_DEA | CPACF_DECRYPT,
   ctx->key, out, in, DES_BLOCK_SIZE);
}

static struct crypto_alg des_alg = {
 .cra_name  = "des",
 .cra_driver_name = "des-s390",
 .cra_priority  = 300,
 .cra_flags  = CRYPTO_ALG_TYPE_CIPHER,
 .cra_blocksize  = DES_BLOCK_SIZE,
 .cra_ctxsize  = sizeof(struct s390_des_ctx),
 .cra_module  = THIS_MODULE,
 .cra_u   = {
  .cipher = {
   .cia_min_keysize = DES_KEY_SIZE,
   .cia_max_keysize = DES_KEY_SIZE,
   .cia_setkey  = des_setkey,
   .cia_encrypt  = s390_des_encrypt,
   .cia_decrypt  = s390_des_decrypt,
  }
 }
};

static int ecb_desall_crypt(struct skcipher_request *req, unsigned long fc)
{
 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm);
 struct skcipher_walk walk;
 unsigned int nbytes, n;
 int ret;

 ret = skcipher_walk_virt(&walk, req, false);
 while ((nbytes = walk.nbytes) != 0) {
  /* only use complete blocks */
  n = nbytes & ~(DES_BLOCK_SIZE - 1);
  cpacf_km(fc, ctx->key, walk.dst.virt.addr,
    walk.src.virt.addr, n);
  ret = skcipher_walk_done(&walk, nbytes - n);
 }
 return ret;
}

static int cbc_desall_crypt(struct skcipher_request *req, unsigned long fc)
{
 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm);
 struct skcipher_walk walk;
 unsigned int nbytes, n;
 int ret;
 struct {
  u8 iv[DES_BLOCK_SIZE];
  u8 key[DES3_KEY_SIZE];
 } param;

 ret = skcipher_walk_virt(&walk, req, false);
 if (ret)
  return ret;
 memcpy(param.iv, walk.iv, DES_BLOCK_SIZE);
 memcpy(param.key, ctx->key, DES3_KEY_SIZE);
 while ((nbytes = walk.nbytes) != 0) {
  /* only use complete blocks */
  n = nbytes & ~(DES_BLOCK_SIZE - 1);
  cpacf_kmc(fc, ¶m, walk.dst.virt.addr,
     walk.src.virt.addr, n);
  memcpy(walk.iv, param.iv, DES_BLOCK_SIZE);
  ret = skcipher_walk_done(&walk, nbytes - n);
 }
 return ret;
}

static int ecb_des_encrypt(struct skcipher_request *req)
{
 return ecb_desall_crypt(req, CPACF_KM_DEA);
}

static int ecb_des_decrypt(struct skcipher_request *req)
{
 return ecb_desall_crypt(req, CPACF_KM_DEA | CPACF_DECRYPT);
}

static struct skcipher_alg ecb_des_alg = {
 .base.cra_name  = "ecb(des)",
 .base.cra_driver_name = "ecb-des-s390",
 .base.cra_priority = 400, /* combo: des + ecb */
 .base.cra_blocksize = DES_BLOCK_SIZE,
 .base.cra_ctxsize = sizeof(struct s390_des_ctx),
 .base.cra_module = THIS_MODULE,
 .min_keysize  = DES_KEY_SIZE,
 .max_keysize  = DES_KEY_SIZE,
 .setkey   = des_setkey_skcipher,
 .encrypt  = ecb_des_encrypt,
 .decrypt  = ecb_des_decrypt,
};

static int cbc_des_encrypt(struct skcipher_request *req)
{
 return cbc_desall_crypt(req, CPACF_KMC_DEA);
}

static int cbc_des_decrypt(struct skcipher_request *req)
{
 return cbc_desall_crypt(req, CPACF_KMC_DEA | CPACF_DECRYPT);
}

static struct skcipher_alg cbc_des_alg = {
 .base.cra_name  = "cbc(des)",
 .base.cra_driver_name = "cbc-des-s390",
 .base.cra_priority = 400, /* combo: des + cbc */
 .base.cra_blocksize = DES_BLOCK_SIZE,
 .base.cra_ctxsize = sizeof(struct s390_des_ctx),
 .base.cra_module = THIS_MODULE,
 .min_keysize  = DES_KEY_SIZE,
 .max_keysize  = DES_KEY_SIZE,
 .ivsize   = DES_BLOCK_SIZE,
 .setkey   = des_setkey_skcipher,
 .encrypt  = cbc_des_encrypt,
 .decrypt  = cbc_des_decrypt,
};

/*
 * RFC2451:
 *
 *   For DES-EDE3, there is no known need to reject weak or
 *   complementation keys.  Any weakness is obviated by the use of
 *   multiple keys.
 *
 *   However, if the first two or last two independent 64-bit keys are
 *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
 *   same as DES.  Implementers MUST reject keys that exhibit this
 *   property.
 *
 *   In fips mode additionally check for all 3 keys are unique.
 *
 */

static int des3_setkey(struct crypto_tfm *tfm, const u8 *key,
         unsigned int key_len)
{
 struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
 int err;

 err = crypto_des3_ede_verify_key(tfm, key);
 if (err)
  return err;

 memcpy(ctx->key, key, key_len);
 return 0;
}

static int des3_setkey_skcipher(struct crypto_skcipher *tfm, const u8 *key,
    unsigned int key_len)
{
 return des3_setkey(crypto_skcipher_tfm(tfm), key, key_len);
}

static void des3_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
 struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);

 cpacf_km(CPACF_KM_TDEA_192, ctx->key, dst, src, DES_BLOCK_SIZE);
}

static void des3_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
 struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);

 cpacf_km(CPACF_KM_TDEA_192 | CPACF_DECRYPT,
   ctx->key, dst, src, DES_BLOCK_SIZE);
}

static struct crypto_alg des3_alg = {
 .cra_name  = "des3_ede",
 .cra_driver_name = "des3_ede-s390",
 .cra_priority  = 300,
 .cra_flags  = CRYPTO_ALG_TYPE_CIPHER,
 .cra_blocksize  = DES_BLOCK_SIZE,
 .cra_ctxsize  = sizeof(struct s390_des_ctx),
 .cra_module  = THIS_MODULE,
 .cra_u   = {
  .cipher = {
   .cia_min_keysize = DES3_KEY_SIZE,
   .cia_max_keysize = DES3_KEY_SIZE,
   .cia_setkey  = des3_setkey,
   .cia_encrypt  = des3_encrypt,
   .cia_decrypt  = des3_decrypt,
  }
 }
};

static int ecb_des3_encrypt(struct skcipher_request *req)
{
 return ecb_desall_crypt(req, CPACF_KM_TDEA_192);
}

static int ecb_des3_decrypt(struct skcipher_request *req)
{
 return ecb_desall_crypt(req, CPACF_KM_TDEA_192 | CPACF_DECRYPT);
}

static struct skcipher_alg ecb_des3_alg = {
 .base.cra_name  = "ecb(des3_ede)",
 .base.cra_driver_name = "ecb-des3_ede-s390",
 .base.cra_priority = 400, /* combo: des3 + ecb */
 .base.cra_blocksize = DES_BLOCK_SIZE,
 .base.cra_ctxsize = sizeof(struct s390_des_ctx),
 .base.cra_module = THIS_MODULE,
 .min_keysize  = DES3_KEY_SIZE,
 .max_keysize  = DES3_KEY_SIZE,
 .setkey   = des3_setkey_skcipher,
 .encrypt  = ecb_des3_encrypt,
 .decrypt  = ecb_des3_decrypt,
};

static int cbc_des3_encrypt(struct skcipher_request *req)
{
 return cbc_desall_crypt(req, CPACF_KMC_TDEA_192);
}

static int cbc_des3_decrypt(struct skcipher_request *req)
{
 return cbc_desall_crypt(req, CPACF_KMC_TDEA_192 | CPACF_DECRYPT);
}

static struct skcipher_alg cbc_des3_alg = {
 .base.cra_name  = "cbc(des3_ede)",
 .base.cra_driver_name = "cbc-des3_ede-s390",
 .base.cra_priority = 400, /* combo: des3 + cbc */
 .base.cra_blocksize = DES_BLOCK_SIZE,
 .base.cra_ctxsize = sizeof(struct s390_des_ctx),
 .base.cra_module = THIS_MODULE,
 .min_keysize  = DES3_KEY_SIZE,
 .max_keysize  = DES3_KEY_SIZE,
 .ivsize   = DES_BLOCK_SIZE,
 .setkey   = des3_setkey_skcipher,
 .encrypt  = cbc_des3_encrypt,
 .decrypt  = cbc_des3_decrypt,
};

static unsigned int __ctrblk_init(u8 *ctrptr, u8 *iv, unsigned int nbytes)
{
 unsigned int i, n;

 /* align to block size, max. PAGE_SIZE */
 n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(DES_BLOCK_SIZE - 1);
 memcpy(ctrptr, iv, DES_BLOCK_SIZE);
 for (i = (n / DES_BLOCK_SIZE) - 1; i > 0; i--) {
  memcpy(ctrptr + DES_BLOCK_SIZE, ctrptr, DES_BLOCK_SIZE);
  crypto_inc(ctrptr + DES_BLOCK_SIZE, DES_BLOCK_SIZE);
  ctrptr += DES_BLOCK_SIZE;
 }
 return n;
}

static int ctr_desall_crypt(struct skcipher_request *req, unsigned long fc)
{
 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 struct s390_des_ctx *ctx = crypto_skcipher_ctx(tfm);
 u8 buf[DES_BLOCK_SIZE], *ctrptr;
 struct skcipher_walk walk;
 unsigned int n, nbytes;
 int ret, locked;

 locked = mutex_trylock(&ctrblk_lock);

 ret = skcipher_walk_virt(&walk, req, false);
 while ((nbytes = walk.nbytes) >= DES_BLOCK_SIZE) {
  n = DES_BLOCK_SIZE;
  if (nbytes >= 2*DES_BLOCK_SIZE && locked)
   n = __ctrblk_init(ctrblk, walk.iv, nbytes);
  ctrptr = (n > DES_BLOCK_SIZE) ? ctrblk : walk.iv;
  cpacf_kmctr(fc, ctx->key, walk.dst.virt.addr,
       walk.src.virt.addr, n, ctrptr);
  if (ctrptr == ctrblk)
   memcpy(walk.iv, ctrptr + n - DES_BLOCK_SIZE,
    DES_BLOCK_SIZE);
  crypto_inc(walk.iv, DES_BLOCK_SIZE);
  ret = skcipher_walk_done(&walk, nbytes - n);
 }
 if (locked)
  mutex_unlock(&ctrblk_lock);
 /* final block may be < DES_BLOCK_SIZE, copy only nbytes */
 if (nbytes) {
  cpacf_kmctr(fc, ctx->key, buf, walk.src.virt.addr,
       DES_BLOCK_SIZE, walk.iv);
  memcpy(walk.dst.virt.addr, buf, nbytes);
  crypto_inc(walk.iv, DES_BLOCK_SIZE);
  ret = skcipher_walk_done(&walk, 0);
 }
 return ret;
}

static int ctr_des_crypt(struct skcipher_request *req)
{
 return ctr_desall_crypt(req, CPACF_KMCTR_DEA);
}

static struct skcipher_alg ctr_des_alg = {
 .base.cra_name  = "ctr(des)",
 .base.cra_driver_name = "ctr-des-s390",
 .base.cra_priority = 400, /* combo: des + ctr */
 .base.cra_blocksize = 1,
 .base.cra_ctxsize = sizeof(struct s390_des_ctx),
 .base.cra_module = THIS_MODULE,
 .min_keysize  = DES_KEY_SIZE,
 .max_keysize  = DES_KEY_SIZE,
 .ivsize   = DES_BLOCK_SIZE,
 .setkey   = des_setkey_skcipher,
 .encrypt  = ctr_des_crypt,
 .decrypt  = ctr_des_crypt,
 .chunksize  = DES_BLOCK_SIZE,
};

static int ctr_des3_crypt(struct skcipher_request *req)
{
 return ctr_desall_crypt(req, CPACF_KMCTR_TDEA_192);
}

static struct skcipher_alg ctr_des3_alg = {
 .base.cra_name  = "ctr(des3_ede)",
 .base.cra_driver_name = "ctr-des3_ede-s390",
 .base.cra_priority = 400, /* combo: des3 + ede */
 .base.cra_blocksize = 1,
 .base.cra_ctxsize = sizeof(struct s390_des_ctx),
 .base.cra_module = THIS_MODULE,
 .min_keysize  = DES3_KEY_SIZE,
 .max_keysize  = DES3_KEY_SIZE,
 .ivsize   = DES_BLOCK_SIZE,
 .setkey   = des3_setkey_skcipher,
 .encrypt  = ctr_des3_crypt,
 .decrypt  = ctr_des3_crypt,
 .chunksize  = DES_BLOCK_SIZE,
};

static struct crypto_alg *des_s390_algs_ptr[2];
static int des_s390_algs_num;
static struct skcipher_alg *des_s390_skciphers_ptr[6];
static int des_s390_skciphers_num;

static int des_s390_register_alg(struct crypto_alg *alg)
{
 int ret;

 ret = crypto_register_alg(alg);
 if (!ret)
  des_s390_algs_ptr[des_s390_algs_num++] = alg;
 return ret;
}

static int des_s390_register_skcipher(struct skcipher_alg *alg)
{
 int ret;

 ret = crypto_register_skcipher(alg);
 if (!ret)
  des_s390_skciphers_ptr[des_s390_skciphers_num++] = alg;
 return ret;
}

static void des_s390_exit(void)
{
 while (des_s390_algs_num--)
  crypto_unregister_alg(des_s390_algs_ptr[des_s390_algs_num]);
 while (des_s390_skciphers_num--)
  crypto_unregister_skcipher(des_s390_skciphers_ptr[des_s390_skciphers_num]);
 if (ctrblk)
  free_page((unsigned long) ctrblk);
}

static int __init des_s390_init(void)
{
 int ret;

 /* Query available functions for KM, KMC and KMCTR */
 cpacf_query(CPACF_KM, &km_functions);
 cpacf_query(CPACF_KMC, &kmc_functions);
 cpacf_query(CPACF_KMCTR, &kmctr_functions);

 if (cpacf_test_func(&km_functions, CPACF_KM_DEA)) {
  ret = des_s390_register_alg(&des_alg);
  if (ret)
   goto out_err;
  ret = des_s390_register_skcipher(&ecb_des_alg);
  if (ret)
   goto out_err;
 }
 if (cpacf_test_func(&kmc_functions, CPACF_KMC_DEA)) {
  ret = des_s390_register_skcipher(&cbc_des_alg);
  if (ret)
   goto out_err;
 }
 if (cpacf_test_func(&km_functions, CPACF_KM_TDEA_192)) {
  ret = des_s390_register_alg(&des3_alg);
  if (ret)
   goto out_err;
  ret = des_s390_register_skcipher(&ecb_des3_alg);
  if (ret)
   goto out_err;
 }
 if (cpacf_test_func(&kmc_functions, CPACF_KMC_TDEA_192)) {
  ret = des_s390_register_skcipher(&cbc_des3_alg);
  if (ret)
   goto out_err;
 }

 if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_DEA) ||
     cpacf_test_func(&kmctr_functions, CPACF_KMCTR_TDEA_192)) {
  ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
  if (!ctrblk) {
   ret = -ENOMEM;
   goto out_err;
  }
 }

 if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_DEA)) {
  ret = des_s390_register_skcipher(&ctr_des_alg);
  if (ret)
   goto out_err;
 }
 if (cpacf_test_func(&kmctr_functions, CPACF_KMCTR_TDEA_192)) {
  ret = des_s390_register_skcipher(&ctr_des3_alg);
  if (ret)
   goto out_err;
 }

 return 0;
out_err:
 des_s390_exit();
 return ret;
}

module_cpu_feature_match(S390_CPU_FEATURE_MSA, des_s390_init);
module_exit(des_s390_exit);

MODULE_ALIAS_CRYPTO("des");
MODULE_ALIAS_CRYPTO("des3_ede");

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");

Messung V0.5
C=98 H=88 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.