summaryrefslogtreecommitdiffstats
path: root/drivers/crypto/imx-scc/scc-blobgen.c
diff options
context:
space:
mode:
authorSteffen Trumtrar <s.trumtrar@pengutronix.de>2016-02-15 11:27:11 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2019-04-12 11:58:39 +0200
commitb62a31a9069b7aa3b01ee08361b683eff4351415 (patch)
tree9e199055d4f12b6e8825254a819216b6dd119808 /drivers/crypto/imx-scc/scc-blobgen.c
parent6f91b9b1994fff3a627633b8883b9ea3fc3acef1 (diff)
downloadbarebox-b62a31a9069b7aa3b01ee08361b683eff4351415.tar.gz
barebox-b62a31a9069b7aa3b01ee08361b683eff4351415.tar.xz
crypto: add new imx-scc driver
The Security Controller (SCC) is found on (at least) i.MX25 SoCs. It is not a crypto engine in the usual sense. The only supported algorithm in hardware is 3DES and the key is not configurable, but is fused in the hardware. The SCC can be handed some block of data in the red memory space and it will return the encrypted data in the black memory space and vice versa. The API for this driver are the functions - mxc_scc_cbc_des_encrypt - mxc_scc_cbc_des_decrypt Along with this driver a blobgen implementation is provided. Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/crypto/imx-scc/scc-blobgen.c')
-rw-r--r--drivers/crypto/imx-scc/scc-blobgen.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/crypto/imx-scc/scc-blobgen.c b/drivers/crypto/imx-scc/scc-blobgen.c
new file mode 100644
index 0000000000..e1a1372420
--- /dev/null
+++ b/drivers/crypto/imx-scc/scc-blobgen.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <common.h>
+#include <dma.h>
+#include <digest.h>
+#include <driver.h>
+#include <init.h>
+#include <blobgen.h>
+#include <stdlib.h>
+#include <crypto.h>
+#include <crypto/sha.h>
+
+#include "scc.h"
+
+#define MAX_IVLEN BLOCKSIZE_BYTES
+
+static struct digest *sha256;
+
+static int sha256sum(uint8_t *src, uint8_t *dst, unsigned int size)
+{
+ if (!sha256)
+ sha256 = digest_alloc("sha256");
+
+ if (!sha256) {
+ pr_err("Unable to allocate sha256 digest\n");
+ return -EINVAL;
+ }
+
+ return digest_digest(sha256, src, size, dst);
+}
+
+static int imx_scc_blob_encrypt(struct blobgen *bg, const char *modifier,
+ const void *plain, int plainsize, void *blob,
+ int *blobsize)
+{
+ char *s;
+ int bufsiz;
+ struct ablkcipher_request req = {};
+ uint8_t iv[MAX_IVLEN];
+ uint8_t hash[SHA256_DIGEST_SIZE];
+ int ret;
+
+ bufsiz = ALIGN(plainsize + KEYMOD_LENGTH, 8);
+
+ s = malloc(bufsiz + SHA256_DIGEST_SIZE);
+ if (!s)
+ return -ENOMEM;
+
+ memset(s, 0, bufsiz);
+
+ strncpy(s, modifier, KEYMOD_LENGTH);
+ memcpy(s + KEYMOD_LENGTH, plain, plainsize);
+
+ ret = sha256sum(s, hash, bufsiz);
+ if (ret)
+ goto out;
+
+ memcpy(s + bufsiz, hash, SHA256_DIGEST_SIZE);
+
+ bufsiz += SHA256_DIGEST_SIZE;
+
+ req.info = iv;
+ req.src = s;
+ req.dst = blob;
+ req.nbytes = bufsiz;
+
+ get_random_bytes(req.info, MAX_IVLEN);
+
+ ret = imx_scc_cbc_des_encrypt(&req);
+ if (ret)
+ goto out;
+
+ memcpy(blob + bufsiz, req.info, MAX_IVLEN);
+ *blobsize = bufsiz + MAX_IVLEN;
+
+out:
+ free(s);
+
+ return ret;
+}
+
+static int imx_scc_blob_decrypt(struct blobgen *bg, const char *modifier,
+ const void *blob, int blobsize, void **plain,
+ int *plainsize)
+{
+ struct ablkcipher_request req = {};
+ uint8_t iv[MAX_IVLEN];
+ uint8_t hash[SHA256_DIGEST_SIZE];
+ int ret;
+ uint8_t *data;
+ int ciphersize = blobsize - MAX_IVLEN;
+
+ if (blobsize <= MAX_IVLEN + SHA256_DIGEST_SIZE + KEYMOD_LENGTH)
+ return -EINVAL;
+
+ data = malloc(ciphersize);
+ if (!data)
+ return -ENOMEM;
+
+ req.info = iv;
+ req.nbytes = ciphersize;
+ req.src = (void *)blob;
+ req.dst = data;
+
+ memcpy(req.info, blob + req.nbytes, MAX_IVLEN);
+
+ ret = imx_scc_cbc_des_decrypt(&req);
+ if (ret)
+ goto out;
+
+ ret = sha256sum(data, hash, ciphersize - SHA256_DIGEST_SIZE);
+ if (ret)
+ goto out;
+
+ if (memcmp(data + ciphersize - SHA256_DIGEST_SIZE, hash,
+ SHA256_DIGEST_SIZE)) {
+ pr_err("%s: Corrupted SHA256 digest. Can't continue.\n",
+ bg->dev.name);
+ pr_err("%s: Calculated hash:\n", bg->dev.name);
+ memory_display(hash, 0, SHA256_DIGEST_SIZE, 1, 0);
+ pr_err("%s: Received hash:\n", bg->dev.name);
+ memory_display(data + ciphersize - SHA256_DIGEST_SIZE,
+ 0, SHA256_DIGEST_SIZE, 1, 0);
+
+ ret = -EILSEQ;
+ goto out;
+ }
+
+ *plainsize = ciphersize - SHA256_DIGEST_SIZE - KEYMOD_LENGTH;
+ *plain = xmemdup(data + KEYMOD_LENGTH, *plainsize);
+out:
+ free(data);
+
+ return ret;
+}
+
+int imx_scc_blob_gen_probe(struct device_d *dev)
+{
+ struct blobgen *bg;
+ int ret;
+
+ bg = xzalloc(sizeof(*bg));
+
+ bg->max_payload_size = MAX_BLOB_LEN - MAX_IVLEN -
+ SHA256_DIGEST_SIZE - KEYMOD_LENGTH;
+ bg->encrypt = imx_scc_blob_encrypt;
+ bg->decrypt = imx_scc_blob_decrypt;
+
+ ret = blob_gen_register(dev, bg);
+ if (ret)
+ free(bg);
+
+ return ret;
+}