Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  eip93-common.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019 - 2021
 *
 * Richard van Schagen <vschagen@icloud.com>
 * Christian Marangi <ansuelsmth@gmail.com
 */


#include <crypto/aes.h>
#include <crypto/ctr.h>
#include <crypto/hmac.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>

#include "eip93-cipher.h"
#include "eip93-hash.h"
#include "eip93-common.h"
#include "eip93-main.h"
#include "eip93-regs.h"

int eip93_parse_ctrl_stat_err(struct eip93_device *eip93, int err)
{
 u32 ext_err;

 if (!err)
  return 0;

 switch (err & ~EIP93_PE_CTRL_PE_EXT_ERR_CODE) {
 case EIP93_PE_CTRL_PE_AUTH_ERR:
 case EIP93_PE_CTRL_PE_PAD_ERR:
  return -EBADMSG;
 /* let software handle anti-replay errors */
 case EIP93_PE_CTRL_PE_SEQNUM_ERR:
  return 0;
 case EIP93_PE_CTRL_PE_EXT_ERR:
  break;
 default:
  dev_err(eip93->dev, "Unhandled error 0x%08x\n", err);
  return -EINVAL;
 }

 /* Parse additional ext errors */
 ext_err = FIELD_GET(EIP93_PE_CTRL_PE_EXT_ERR_CODE, err);
 switch (ext_err) {
 case EIP93_PE_CTRL_PE_EXT_ERR_BUS:
 case EIP93_PE_CTRL_PE_EXT_ERR_PROCESSING:
  return -EIO;
 case EIP93_PE_CTRL_PE_EXT_ERR_DESC_OWNER:
  return -EACCES;
 case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_OP:
 case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_ALGO:
 case EIP93_PE_CTRL_PE_EXT_ERR_SPI:
  return -EINVAL;
 case EIP93_PE_CTRL_PE_EXT_ERR_ZERO_LENGTH:
 case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_PK_LENGTH:
 case EIP93_PE_CTRL_PE_EXT_ERR_BLOCK_SIZE_ERR:
  return -EBADMSG;
 default:
  dev_err(eip93->dev, "Unhandled ext error 0x%08x\n", ext_err);
  return -EINVAL;
 }
}

static void *eip93_ring_next_wptr(struct eip93_device *eip93,
      struct eip93_desc_ring *ring)
{
 void *ptr = ring->write;

 if ((ring->write == ring->read - ring->offset) ||
     (ring->read == ring->base && ring->write == ring->base_end))
  return ERR_PTR(-ENOMEM);

 if (ring->write == ring->base_end)
  ring->write = ring->base;
 else
  ring->write += ring->offset;

 return ptr;
}

static void *eip93_ring_next_rptr(struct eip93_device *eip93,
      struct eip93_desc_ring *ring)
{
 void *ptr = ring->read;

 if (ring->write == ring->read)
  return ERR_PTR(-ENOENT);

 if (ring->read == ring->base_end)
  ring->read = ring->base;
 else
  ring->read += ring->offset;

 return ptr;
}

int eip93_put_descriptor(struct eip93_device *eip93,
    struct eip93_descriptor *desc)
{
 struct eip93_descriptor *cdesc;
 struct eip93_descriptor *rdesc;

 rdesc = eip93_ring_next_wptr(eip93, &eip93->ring->rdr);
 if (IS_ERR(rdesc))
  return -ENOENT;

 cdesc = eip93_ring_next_wptr(eip93, &eip93->ring->cdr);
 if (IS_ERR(cdesc))
  return -ENOENT;

 memset(rdesc, 0, sizeof(struct eip93_descriptor));

 memcpy(cdesc, desc, sizeof(struct eip93_descriptor));

 return 0;
}

void *eip93_get_descriptor(struct eip93_device *eip93)
{
 struct eip93_descriptor *cdesc;
 void *ptr;

 cdesc = eip93_ring_next_rptr(eip93, &eip93->ring->cdr);
 if (IS_ERR(cdesc))
  return ERR_PTR(-ENOENT);

 memset(cdesc, 0, sizeof(struct eip93_descriptor));

 ptr = eip93_ring_next_rptr(eip93, &eip93->ring->rdr);
 if (IS_ERR(ptr))
  return ERR_PTR(-ENOENT);

 return ptr;
}

static void eip93_free_sg_copy(const int len, struct scatterlist **sg)
{
 if (!*sg || !len)
  return;

 free_pages((unsigned long)sg_virt(*sg), get_order(len));
 kfree(*sg);
 *sg = NULL;
}

static int eip93_make_sg_copy(struct scatterlist *src, struct scatterlist **dst,
         const u32 len, const bool copy)
{
 void *pages;

 *dst = kmalloc(sizeof(**dst), GFP_KERNEL);
 if (!*dst)
  return -ENOMEM;

 pages = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA,
      get_order(len));
 if (!pages) {
  kfree(*dst);
  *dst = NULL;
  return -ENOMEM;
 }

 sg_init_table(*dst, 1);
 sg_set_buf(*dst, pages, len);

 /* copy only as requested */
 if (copy)
  sg_copy_to_buffer(src, sg_nents(src), pages, len);

 return 0;
}

static bool eip93_is_sg_aligned(struct scatterlist *sg, u32 len,
    const int blksize)
{
 int nents;

 for (nents = 0; sg; sg = sg_next(sg), ++nents) {
  if (!IS_ALIGNED(sg->offset, 4))
   return false;

  if (len <= sg->length) {
   if (!IS_ALIGNED(len, blksize))
    return false;

   return true;
  }

  if (!IS_ALIGNED(sg->length, blksize))
   return false;

  len -= sg->length;
 }
 return false;
}

int check_valid_request(struct eip93_cipher_reqctx *rctx)
{
 struct scatterlist *src = rctx->sg_src;
 struct scatterlist *dst = rctx->sg_dst;
 u32 textsize = rctx->textsize;
 u32 authsize = rctx->authsize;
 u32 blksize = rctx->blksize;
 u32 totlen_src = rctx->assoclen + rctx->textsize;
 u32 totlen_dst = rctx->assoclen + rctx->textsize;
 u32 copy_len;
 bool src_align, dst_align;
 int src_nents, dst_nents;
 int err = -EINVAL;

 if (!IS_CTR(rctx->flags)) {
  if (!IS_ALIGNED(textsize, blksize))
   return err;
 }

 if (authsize) {
  if (IS_ENCRYPT(rctx->flags))
   totlen_dst += authsize;
  else
   totlen_src += authsize;
 }

 src_nents = sg_nents_for_len(src, totlen_src);
 if (src_nents < 0)
  return src_nents;

 dst_nents = sg_nents_for_len(dst, totlen_dst);
 if (dst_nents < 0)
  return dst_nents;

 if (src == dst) {
  src_nents = max(src_nents, dst_nents);
  dst_nents = src_nents;
  if (unlikely((totlen_src || totlen_dst) && !src_nents))
   return err;

 } else {
  if (unlikely(totlen_src && !src_nents))
   return err;

  if (unlikely(totlen_dst && !dst_nents))
   return err;
 }

 if (authsize) {
  if (dst_nents == 1 && src_nents == 1) {
   src_align = eip93_is_sg_aligned(src, totlen_src, blksize);
   if (src ==  dst)
    dst_align = src_align;
   else
    dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize);
  } else {
   src_align = false;
   dst_align = false;
  }
 } else {
  src_align = eip93_is_sg_aligned(src, totlen_src, blksize);
  if (src == dst)
   dst_align = src_align;
  else
   dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize);
 }

 copy_len = max(totlen_src, totlen_dst);
 if (!src_align) {
  err = eip93_make_sg_copy(src, &rctx->sg_src, copy_len, true);
  if (err)
   return err;
 }

 if (!dst_align) {
  err = eip93_make_sg_copy(dst, &rctx->sg_dst, copy_len, false);
  if (err)
   return err;
 }

 src_nents = sg_nents_for_len(rctx->sg_src, totlen_src);
 if (src_nents < 0)
  return src_nents;

 dst_nents = sg_nents_for_len(rctx->sg_dst, totlen_dst);
 if (dst_nents < 0)
  return dst_nents;

 rctx->src_nents = src_nents;
 rctx->dst_nents = dst_nents;

 return 0;
}

/*
 * Set sa_record function:
 * Even sa_record is set to "0", keep " = 0" for readability.
 */

void eip93_set_sa_record(struct sa_record *sa_record, const unsigned int keylen,
    const u32 flags)
{
 /* Reset cmd word */
 sa_record->sa_cmd0_word = 0;
 sa_record->sa_cmd1_word = 0;

 sa_record->sa_cmd0_word |= EIP93_SA_CMD_IV_FROM_STATE;
 if (!IS_ECB(flags))
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_SAVE_IV;

 sa_record->sa_cmd0_word |= EIP93_SA_CMD_OP_BASIC;

 switch ((flags & EIP93_ALG_MASK)) {
 case EIP93_ALG_AES:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_AES;
  sa_record->sa_cmd1_word |= FIELD_PREP(EIP93_SA_CMD_AES_KEY_LENGTH,
            keylen >> 3);
  break;
 case EIP93_ALG_3DES:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_3DES;
  break;
 case EIP93_ALG_DES:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_DES;
  break;
 default:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_NULL;
 }

 switch ((flags & EIP93_HASH_MASK)) {
 case EIP93_HASH_SHA256:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA256;
  break;
 case EIP93_HASH_SHA224:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA224;
  break;
 case EIP93_HASH_SHA1:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA1;
  break;
 case EIP93_HASH_MD5:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_MD5;
  break;
 default:
  sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_NULL;
 }

 sa_record->sa_cmd0_word |= EIP93_SA_CMD_PAD_ZERO;

 switch ((flags & EIP93_MODE_MASK)) {
 case EIP93_MODE_CBC:
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CBC;
  break;
 case EIP93_MODE_CTR:
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CTR;
  break;
 case EIP93_MODE_ECB:
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_ECB;
  break;
 }

 sa_record->sa_cmd0_word |= EIP93_SA_CMD_DIGEST_3WORD;
 if (IS_HASH(flags)) {
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_PAD;
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_DIGEST;
 }

 if (IS_HMAC(flags)) {
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_HMAC;
  sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_HEADER;
 }

 sa_record->sa_spi = 0x0;
 sa_record->sa_seqmum_mask[0] = 0xFFFFFFFF;
 sa_record->sa_seqmum_mask[1] = 0x0;
}

/*
 * Poor mans Scatter/gather function:
 * Create a Descriptor for every segment to avoid copying buffers.
 * For performance better to wait for hardware to perform multiple DMA
 */

static int eip93_scatter_combine(struct eip93_device *eip93,
     struct eip93_cipher_reqctx *rctx,
     u32 datalen, u32 split, int offsetin)
{
 struct eip93_descriptor *cdesc = rctx->cdesc;
 struct scatterlist *sgsrc = rctx->sg_src;
 struct scatterlist *sgdst = rctx->sg_dst;
 unsigned int remainin = sg_dma_len(sgsrc);
 unsigned int remainout = sg_dma_len(sgdst);
 dma_addr_t saddr = sg_dma_address(sgsrc);
 dma_addr_t daddr = sg_dma_address(sgdst);
 dma_addr_t state_addr;
 u32 src_addr, dst_addr, len, n;
 bool nextin = false;
 bool nextout = false;
 int offsetout = 0;
 int err;

 if (IS_ECB(rctx->flags))
  rctx->sa_state_base = 0;

 if (split < datalen) {
  state_addr = rctx->sa_state_ctr_base;
  n = split;
 } else {
  state_addr = rctx->sa_state_base;
  n = datalen;
 }

 do {
  if (nextin) {
   sgsrc = sg_next(sgsrc);
   remainin = sg_dma_len(sgsrc);
   if (remainin == 0)
    continue;

   saddr = sg_dma_address(sgsrc);
   offsetin = 0;
   nextin = false;
  }

  if (nextout) {
   sgdst = sg_next(sgdst);
   remainout = sg_dma_len(sgdst);
   if (remainout == 0)
    continue;

   daddr = sg_dma_address(sgdst);
   offsetout = 0;
   nextout = false;
  }
  src_addr = saddr + offsetin;
  dst_addr = daddr + offsetout;

  if (remainin == remainout) {
   len = remainin;
   if (len > n) {
    len = n;
    remainin -= n;
    remainout -= n;
    offsetin += n;
    offsetout += n;
   } else {
    nextin = true;
    nextout = true;
   }
  } else if (remainin < remainout) {
   len = remainin;
   if (len > n) {
    len = n;
    remainin -= n;
    remainout -= n;
    offsetin += n;
    offsetout += n;
   } else {
    offsetout += len;
    remainout -= len;
    nextin = true;
   }
  } else {
   len = remainout;
   if (len > n) {
    len = n;
    remainin -= n;
    remainout -= n;
    offsetin += n;
    offsetout += n;
   } else {
    offsetin += len;
    remainin -= len;
    nextout = true;
   }
  }
  n -= len;

  cdesc->src_addr = src_addr;
  cdesc->dst_addr = dst_addr;
  cdesc->state_addr = state_addr;
  cdesc->pe_length_word = FIELD_PREP(EIP93_PE_LENGTH_HOST_PE_READY,
         EIP93_PE_LENGTH_HOST_READY);
  cdesc->pe_length_word |= FIELD_PREP(EIP93_PE_LENGTH_LENGTH, len);

  if (n == 0) {
   n = datalen - split;
   split = datalen;
   state_addr = rctx->sa_state_base;
  }

  if (n == 0)
   cdesc->user_id |= FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS,
           EIP93_DESC_LAST);

  /*
 * Loop - Delay - No need to rollback
 * Maybe refine by slowing down at EIP93_RING_BUSY
 */

again:
  scoped_guard(spinlock_irqsave, &eip93->ring->write_lock)
   err = eip93_put_descriptor(eip93, cdesc);
  if (err) {
   usleep_range(EIP93_RING_BUSY_DELAY,
         EIP93_RING_BUSY_DELAY * 2);
   goto again;
  }
  /* Writing new descriptor count starts DMA action */
  writel(1, eip93->base + EIP93_REG_PE_CD_COUNT);
 } while (n);

 return -EINPROGRESS;
}

int eip93_send_req(struct crypto_async_request *async,
     const u8 *reqiv, struct eip93_cipher_reqctx *rctx)
{
 struct eip93_crypto_ctx *ctx = crypto_tfm_ctx(async->tfm);
 struct eip93_device *eip93 = ctx->eip93;
 struct scatterlist *src = rctx->sg_src;
 struct scatterlist *dst = rctx->sg_dst;
 struct sa_state *sa_state;
 struct eip93_descriptor cdesc;
 u32 flags = rctx->flags;
 int offsetin = 0, err;
 u32 datalen = rctx->assoclen + rctx->textsize;
 u32 split = datalen;
 u32 start, end, ctr, blocks;
 u32 iv[AES_BLOCK_SIZE / sizeof(u32)];
 int crypto_async_idr;

 rctx->sa_state_ctr = NULL;
 rctx->sa_state = NULL;

 if (IS_ECB(flags))
  goto skip_iv;

 memcpy(iv, reqiv, rctx->ivsize);

 rctx->sa_state = kzalloc(sizeof(*rctx->sa_state), GFP_KERNEL);
 if (!rctx->sa_state)
  return -ENOMEM;

 sa_state = rctx->sa_state;

 memcpy(sa_state->state_iv, iv, rctx->ivsize);
 if (IS_RFC3686(flags)) {
  sa_state->state_iv[0] = ctx->sa_nonce;
  sa_state->state_iv[1] = iv[0];
  sa_state->state_iv[2] = iv[1];
  sa_state->state_iv[3] = (u32 __force)cpu_to_be32(0x1);
 } else if (!IS_HMAC(flags) && IS_CTR(flags)) {
  /* Compute data length. */
  blocks = DIV_ROUND_UP(rctx->textsize, AES_BLOCK_SIZE);
  ctr = be32_to_cpu((__be32 __force)iv[3]);
  /* Check 32bit counter overflow. */
  start = ctr;
  end = start + blocks - 1;
  if (end < start) {
   split = AES_BLOCK_SIZE * -start;
   /*
 * Increment the counter manually to cope with
 * the hardware counter overflow.
 */

   iv[3] = 0xffffffff;
   crypto_inc((u8 *)iv, AES_BLOCK_SIZE);

   rctx->sa_state_ctr = kzalloc(sizeof(*rctx->sa_state_ctr),
           GFP_KERNEL);
   if (!rctx->sa_state_ctr) {
    err = -ENOMEM;
    goto free_sa_state;
   }

   memcpy(rctx->sa_state_ctr->state_iv, reqiv, rctx->ivsize);
   memcpy(sa_state->state_iv, iv, rctx->ivsize);

   rctx->sa_state_ctr_base = dma_map_single(eip93->dev, rctx->sa_state_ctr,
         sizeof(*rctx->sa_state_ctr),
         DMA_TO_DEVICE);
   err = dma_mapping_error(eip93->dev, rctx->sa_state_ctr_base);
   if (err)
    goto free_sa_state_ctr;
  }
 }

 rctx->sa_state_base = dma_map_single(eip93->dev, rctx->sa_state,
          sizeof(*rctx->sa_state), DMA_TO_DEVICE);
 err = dma_mapping_error(eip93->dev, rctx->sa_state_base);
 if (err)
  goto free_sa_state_ctr_dma;

skip_iv:

 cdesc.pe_ctrl_stat_word = FIELD_PREP(EIP93_PE_CTRL_PE_READY_DES_TRING_OWN,
          EIP93_PE_CTRL_HOST_READY);
 cdesc.sa_addr = rctx->sa_record_base;
 cdesc.arc4_addr = 0;

 scoped_guard(spinlock_bh, &eip93->ring->idr_lock)
  crypto_async_idr = idr_alloc(&eip93->ring->crypto_async_idr, async, 0,
          EIP93_RING_NUM - 1, GFP_ATOMIC);

 cdesc.user_id = FIELD_PREP(EIP93_PE_USER_ID_CRYPTO_IDR, (u16)crypto_async_idr) |
   FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS, rctx->desc_flags);

 rctx->cdesc = &cdesc;

 /* map DMA_BIDIRECTIONAL to invalidate cache on destination
 * implies __dma_cache_wback_inv
 */

 if (!dma_map_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL)) {
  err = -ENOMEM;
  goto free_sa_state_ctr_dma;
 }

 if (src != dst &&
     !dma_map_sg(eip93->dev, src, rctx->src_nents, DMA_TO_DEVICE)) {
  err = -ENOMEM;
  goto free_sg_dma;
 }

 return eip93_scatter_combine(eip93, rctx, datalen, split, offsetin);

free_sg_dma:
 dma_unmap_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL);
free_sa_state_ctr_dma:
 if (rctx->sa_state_ctr)
  dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base,
     sizeof(*rctx->sa_state_ctr),
     DMA_TO_DEVICE);
free_sa_state_ctr:
 kfree(rctx->sa_state_ctr);
 if (rctx->sa_state)
  dma_unmap_single(eip93->dev, rctx->sa_state_base,
     sizeof(*rctx->sa_state),
     DMA_TO_DEVICE);
free_sa_state:
 kfree(rctx->sa_state);

 return err;
}

void eip93_unmap_dma(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx,
       struct scatterlist *reqsrc, struct scatterlist *reqdst)
{
 u32 len = rctx->assoclen + rctx->textsize;
 u32 authsize = rctx->authsize;
 u32 flags = rctx->flags;
 u32 *otag;
 int i;

 if (rctx->sg_src == rctx->sg_dst) {
  dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents,
        DMA_BIDIRECTIONAL);
  goto process_tag;
 }

 dma_unmap_sg(eip93->dev, rctx->sg_src, rctx->src_nents,
       DMA_TO_DEVICE);

 if (rctx->sg_src != reqsrc)
  eip93_free_sg_copy(len +  rctx->authsize, &rctx->sg_src);

 dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents,
       DMA_BIDIRECTIONAL);

 /* SHA tags need conversion from net-to-host */
process_tag:
 if (IS_DECRYPT(flags))
  authsize = 0;

 if (authsize) {
  if (!IS_HASH_MD5(flags)) {
   otag = sg_virt(rctx->sg_dst) + len;
   for (i = 0; i < (authsize / 4); i++)
    otag[i] = be32_to_cpu((__be32 __force)otag[i]);
  }
 }

 if (rctx->sg_dst != reqdst) {
  sg_copy_from_buffer(reqdst, sg_nents(reqdst),
        sg_virt(rctx->sg_dst), len + authsize);
  eip93_free_sg_copy(len + rctx->authsize, &rctx->sg_dst);
 }
}

void eip93_handle_result(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx,
    u8 *reqiv)
{
 if (rctx->sa_state_ctr)
  dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base,
     sizeof(*rctx->sa_state_ctr),
     DMA_FROM_DEVICE);

 if (rctx->sa_state)
  dma_unmap_single(eip93->dev, rctx->sa_state_base,
     sizeof(*rctx->sa_state),
     DMA_FROM_DEVICE);

 if (!IS_ECB(rctx->flags))
  memcpy(reqiv, rctx->sa_state->state_iv, rctx->ivsize);

 kfree(rctx->sa_state_ctr);
 kfree(rctx->sa_state);
}

int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen,
        unsigned int hashlen, u8 *dest_ipad, u8 *dest_opad,
        bool skip_ipad)
{
 u8 ipad[SHA256_BLOCK_SIZE], opad[SHA256_BLOCK_SIZE];
 struct crypto_ahash *ahash_tfm;
 struct eip93_hash_reqctx *rctx;
 struct ahash_request *req;
 DECLARE_CRYPTO_WAIT(wait);
 struct scatterlist sg[1];
 const char *alg_name;
 int i, ret;

 switch (ctx_flags & EIP93_HASH_MASK) {
 case EIP93_HASH_SHA256:
  alg_name = "sha256-eip93";
  break;
 case EIP93_HASH_SHA224:
  alg_name = "sha224-eip93";
  break;
 case EIP93_HASH_SHA1:
  alg_name = "sha1-eip93";
  break;
 case EIP93_HASH_MD5:
  alg_name = "md5-eip93";
  break;
 default/* Impossible */
  return -EINVAL;
 }

 ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC);
 if (IS_ERR(ahash_tfm))
  return PTR_ERR(ahash_tfm);

 req = ahash_request_alloc(ahash_tfm, GFP_ATOMIC);
 if (!req) {
  ret = -ENOMEM;
  goto err_ahash;
 }

 rctx = ahash_request_ctx_dma(req);
 crypto_init_wait(&wait);
 ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
       crypto_req_done, &wait);

 /* Hash the key if > SHA256_BLOCK_SIZE */
 if (keylen > SHA256_BLOCK_SIZE) {
  sg_init_one(&sg[0], key, keylen);

  ahash_request_set_crypt(req, sg, ipad, keylen);
  ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
  if (ret)
   goto err_req;

  keylen = hashlen;
 } else {
  memcpy(ipad, key, keylen);
 }

 /* Copy to opad */
 memset(ipad + keylen, 0, SHA256_BLOCK_SIZE - keylen);
 memcpy(opad, ipad, SHA256_BLOCK_SIZE);

 /* Pad with HMAC constants */
 for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
  ipad[i] ^= HMAC_IPAD_VALUE;
  opad[i] ^= HMAC_OPAD_VALUE;
 }

 if (skip_ipad) {
  memcpy(dest_ipad, ipad, SHA256_BLOCK_SIZE);
 } else {
  /* Hash ipad */
  sg_init_one(&sg[0], ipad, SHA256_BLOCK_SIZE);
  ahash_request_set_crypt(req, sg, dest_ipad, SHA256_BLOCK_SIZE);
  ret = crypto_ahash_init(req);
  if (ret)
   goto err_req;

  /* Disable HASH_FINALIZE for ipad hash */
  rctx->partial_hash = true;

  ret = crypto_wait_req(crypto_ahash_finup(req), &wait);
  if (ret)
   goto err_req;
 }

 /* Hash opad */
 sg_init_one(&sg[0], opad, SHA256_BLOCK_SIZE);
 ahash_request_set_crypt(req, sg, dest_opad, SHA256_BLOCK_SIZE);
 ret = crypto_ahash_init(req);
 if (ret)
  goto err_req;

 /* Disable HASH_FINALIZE for opad hash */
 rctx->partial_hash = true;

 ret = crypto_wait_req(crypto_ahash_finup(req), &wait);
 if (ret)
  goto err_req;

 if (!IS_HASH_MD5(ctx_flags)) {
  for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) {
   u32 *ipad_hash = (u32 *)dest_ipad;
   u32 *opad_hash = (u32 *)dest_opad;

   if (!skip_ipad)
    ipad_hash[i] = (u32 __force)cpu_to_be32(ipad_hash[i]);
   opad_hash[i] = (u32 __force)cpu_to_be32(opad_hash[i]);
  }
 }

err_req:
 ahash_request_free(req);
err_ahash:
 crypto_free_ahash(ahash_tfm);

 return ret;
}

Messung V0.5
C=98 H=90 G=94

¤ Dauer der Verarbeitung: 0.13 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge