initramfs: break loop when decompression finishes
[platform/kernel/linux-rpi.git] / crypto / akcipher.c
index 7960ceb..52813f0 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/scatterlist.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -17,6 +18,8 @@
 
 #include "internal.h"
 
+#define CRYPTO_ALG_TYPE_AHASH_MASK     0x0000000e
+
 static int __maybe_unused crypto_akcipher_report(
        struct sk_buff *skb, struct crypto_alg *alg)
 {
@@ -105,7 +108,7 @@ static const struct crypto_type crypto_akcipher_type = {
        .report_stat = crypto_akcipher_report_stat,
 #endif
        .maskclear = ~CRYPTO_ALG_TYPE_MASK,
-       .maskset = CRYPTO_ALG_TYPE_MASK,
+       .maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
        .type = CRYPTO_ALG_TYPE_AKCIPHER,
        .tfmsize = offsetof(struct crypto_akcipher, base),
 };
@@ -186,5 +189,124 @@ int akcipher_register_instance(struct crypto_template *tmpl,
 }
 EXPORT_SYMBOL_GPL(akcipher_register_instance);
 
+int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data)
+{
+       unsigned int reqsize = crypto_akcipher_reqsize(data->tfm);
+       struct akcipher_request *req;
+       struct scatterlist *sg;
+       unsigned int mlen;
+       unsigned int len;
+       u8 *buf;
+
+       if (data->dst)
+               mlen = max(data->slen, data->dlen);
+       else
+               mlen = data->slen + data->dlen;
+
+       len = sizeof(*req) + reqsize + mlen;
+       if (len < mlen)
+               return -EOVERFLOW;
+
+       req = kzalloc(len, GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       data->req = req;
+       akcipher_request_set_tfm(req, data->tfm);
+
+       buf = (u8 *)(req + 1) + reqsize;
+       data->buf = buf;
+       memcpy(buf, data->src, data->slen);
+
+       sg = &data->sg;
+       sg_init_one(sg, buf, mlen);
+       akcipher_request_set_crypt(req, sg, data->dst ? sg : NULL,
+                                  data->slen, data->dlen);
+
+       crypto_init_wait(&data->cwait);
+       akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
+                                     crypto_req_done, &data->cwait);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_akcipher_sync_prep);
+
+int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err)
+{
+       err = crypto_wait_req(err, &data->cwait);
+       if (data->dst)
+               memcpy(data->dst, data->buf, data->dlen);
+       data->dlen = data->req->dst_len;
+       kfree_sensitive(data->req);
+       return err;
+}
+EXPORT_SYMBOL_GPL(crypto_akcipher_sync_post);
+
+int crypto_akcipher_sync_encrypt(struct crypto_akcipher *tfm,
+                                const void *src, unsigned int slen,
+                                void *dst, unsigned int dlen)
+{
+       struct crypto_akcipher_sync_data data = {
+               .tfm = tfm,
+               .src = src,
+               .dst = dst,
+               .slen = slen,
+               .dlen = dlen,
+       };
+
+       return crypto_akcipher_sync_prep(&data) ?:
+              crypto_akcipher_sync_post(&data,
+                                        crypto_akcipher_encrypt(data.req));
+}
+EXPORT_SYMBOL_GPL(crypto_akcipher_sync_encrypt);
+
+int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm,
+                                const void *src, unsigned int slen,
+                                void *dst, unsigned int dlen)
+{
+       struct crypto_akcipher_sync_data data = {
+               .tfm = tfm,
+               .src = src,
+               .dst = dst,
+               .slen = slen,
+               .dlen = dlen,
+       };
+
+       return crypto_akcipher_sync_prep(&data) ?:
+              crypto_akcipher_sync_post(&data,
+                                        crypto_akcipher_decrypt(data.req)) ?:
+              data.dlen;
+}
+EXPORT_SYMBOL_GPL(crypto_akcipher_sync_decrypt);
+
+static void crypto_exit_akcipher_ops_sig(struct crypto_tfm *tfm)
+{
+       struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_akcipher(*ctx);
+}
+
+int crypto_init_akcipher_ops_sig(struct crypto_tfm *tfm)
+{
+       struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm);
+       struct crypto_alg *calg = tfm->__crt_alg;
+       struct crypto_akcipher *akcipher;
+
+       if (!crypto_mod_get(calg))
+               return -EAGAIN;
+
+       akcipher = crypto_create_tfm(calg, &crypto_akcipher_type);
+       if (IS_ERR(akcipher)) {
+               crypto_mod_put(calg);
+               return PTR_ERR(akcipher);
+       }
+
+       *ctx = akcipher;
+       tfm->exit = crypto_exit_akcipher_ops_sig;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_init_akcipher_ops_sig);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic public key cipher type");