diff options
author | Cyrille Pitchen <cyrille.pitchen@atmel.com> | 2016-10-03 08:33:16 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2016-10-20 23:03:39 -0400 |
commit | d52db5188a87dcdf8e5bf024f45543b362a1a85f (patch) | |
tree | b11af2064e8b640cd8307d004361bc298a16bfb6 /drivers/crypto/atmel-aes.c | |
parent | f709dc86bc4f9d8c320ceb9a12ac304756129dd5 (diff) |
crypto: atmel-aes - add support to the XTS mode
This patch adds the xts(aes) algorithm, which is supported from
hardware version 0x500 and above (sama5d2x).
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/atmel-aes.c')
-rw-r--r-- | drivers/crypto/atmel-aes.c | 185 |
1 files changed, 179 insertions, 6 deletions
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 1d9e7bd3f377..6b656f4a9378 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <crypto/scatterwalk.h> | 36 | #include <crypto/scatterwalk.h> |
37 | #include <crypto/algapi.h> | 37 | #include <crypto/algapi.h> |
38 | #include <crypto/aes.h> | 38 | #include <crypto/aes.h> |
39 | #include <crypto/xts.h> | ||
39 | #include <crypto/internal/aead.h> | 40 | #include <crypto/internal/aead.h> |
40 | #include <linux/platform_data/crypto-atmel.h> | 41 | #include <linux/platform_data/crypto-atmel.h> |
41 | #include <dt-bindings/dma/at91.h> | 42 | #include <dt-bindings/dma/at91.h> |
@@ -68,6 +69,7 @@ | |||
68 | #define AES_FLAGS_CFB8 (AES_MR_OPMOD_CFB | AES_MR_CFBS_8b) | 69 | #define AES_FLAGS_CFB8 (AES_MR_OPMOD_CFB | AES_MR_CFBS_8b) |
69 | #define AES_FLAGS_CTR AES_MR_OPMOD_CTR | 70 | #define AES_FLAGS_CTR AES_MR_OPMOD_CTR |
70 | #define AES_FLAGS_GCM AES_MR_OPMOD_GCM | 71 | #define AES_FLAGS_GCM AES_MR_OPMOD_GCM |
72 | #define AES_FLAGS_XTS AES_MR_OPMOD_XTS | ||
71 | 73 | ||
72 | #define AES_FLAGS_MODE_MASK (AES_FLAGS_OPMODE_MASK | \ | 74 | #define AES_FLAGS_MODE_MASK (AES_FLAGS_OPMODE_MASK | \ |
73 | AES_FLAGS_ENCRYPT | \ | 75 | AES_FLAGS_ENCRYPT | \ |
@@ -89,6 +91,7 @@ struct atmel_aes_caps { | |||
89 | bool has_cfb64; | 91 | bool has_cfb64; |
90 | bool has_ctr32; | 92 | bool has_ctr32; |
91 | bool has_gcm; | 93 | bool has_gcm; |
94 | bool has_xts; | ||
92 | u32 max_burst_size; | 95 | u32 max_burst_size; |
93 | }; | 96 | }; |
94 | 97 | ||
@@ -135,6 +138,12 @@ struct atmel_aes_gcm_ctx { | |||
135 | atmel_aes_fn_t ghash_resume; | 138 | atmel_aes_fn_t ghash_resume; |
136 | }; | 139 | }; |
137 | 140 | ||
141 | struct atmel_aes_xts_ctx { | ||
142 | struct atmel_aes_base_ctx base; | ||
143 | |||
144 | u32 key2[AES_KEYSIZE_256 / sizeof(u32)]; | ||
145 | }; | ||
146 | |||
138 | struct atmel_aes_reqctx { | 147 | struct atmel_aes_reqctx { |
139 | unsigned long mode; | 148 | unsigned long mode; |
140 | }; | 149 | }; |
@@ -282,6 +291,20 @@ static const char *atmel_aes_reg_name(u32 offset, char *tmp, size_t sz) | |||
282 | snprintf(tmp, sz, "GCMHR[%u]", (offset - AES_GCMHR(0)) >> 2); | 291 | snprintf(tmp, sz, "GCMHR[%u]", (offset - AES_GCMHR(0)) >> 2); |
283 | break; | 292 | break; |
284 | 293 | ||
294 | case AES_TWR(0): | ||
295 | case AES_TWR(1): | ||
296 | case AES_TWR(2): | ||
297 | case AES_TWR(3): | ||
298 | snprintf(tmp, sz, "TWR[%u]", (offset - AES_TWR(0)) >> 2); | ||
299 | break; | ||
300 | |||
301 | case AES_ALPHAR(0): | ||
302 | case AES_ALPHAR(1): | ||
303 | case AES_ALPHAR(2): | ||
304 | case AES_ALPHAR(3): | ||
305 | snprintf(tmp, sz, "ALPHAR[%u]", (offset - AES_ALPHAR(0)) >> 2); | ||
306 | break; | ||
307 | |||
285 | default: | 308 | default: |
286 | snprintf(tmp, sz, "0x%02x", offset); | 309 | snprintf(tmp, sz, "0x%02x", offset); |
287 | break; | 310 | break; |
@@ -453,15 +476,15 @@ static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err) | |||
453 | return err; | 476 | return err; |
454 | } | 477 | } |
455 | 478 | ||
456 | static void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma, | 479 | static void atmel_aes_write_ctrl_key(struct atmel_aes_dev *dd, bool use_dma, |
457 | const u32 *iv) | 480 | const u32 *iv, const u32 *key, int keylen) |
458 | { | 481 | { |
459 | u32 valmr = 0; | 482 | u32 valmr = 0; |
460 | 483 | ||
461 | /* MR register must be set before IV registers */ | 484 | /* MR register must be set before IV registers */ |
462 | if (dd->ctx->keylen == AES_KEYSIZE_128) | 485 | if (keylen == AES_KEYSIZE_128) |
463 | valmr |= AES_MR_KEYSIZE_128; | 486 | valmr |= AES_MR_KEYSIZE_128; |
464 | else if (dd->ctx->keylen == AES_KEYSIZE_192) | 487 | else if (keylen == AES_KEYSIZE_192) |
465 | valmr |= AES_MR_KEYSIZE_192; | 488 | valmr |= AES_MR_KEYSIZE_192; |
466 | else | 489 | else |
467 | valmr |= AES_MR_KEYSIZE_256; | 490 | valmr |= AES_MR_KEYSIZE_256; |
@@ -478,13 +501,19 @@ static void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma, | |||
478 | 501 | ||
479 | atmel_aes_write(dd, AES_MR, valmr); | 502 | atmel_aes_write(dd, AES_MR, valmr); |
480 | 503 | ||
481 | atmel_aes_write_n(dd, AES_KEYWR(0), dd->ctx->key, | 504 | atmel_aes_write_n(dd, AES_KEYWR(0), key, SIZE_IN_WORDS(keylen)); |
482 | SIZE_IN_WORDS(dd->ctx->keylen)); | ||
483 | 505 | ||
484 | if (iv && (valmr & AES_MR_OPMOD_MASK) != AES_MR_OPMOD_ECB) | 506 | if (iv && (valmr & AES_MR_OPMOD_MASK) != AES_MR_OPMOD_ECB) |
485 | atmel_aes_write_block(dd, AES_IVR(0), iv); | 507 | atmel_aes_write_block(dd, AES_IVR(0), iv); |
486 | } | 508 | } |
487 | 509 | ||
510 | static inline void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma, | ||
511 | const u32 *iv) | ||
512 | |||
513 | { | ||
514 | atmel_aes_write_ctrl_key(dd, use_dma, iv, | ||
515 | dd->ctx->key, dd->ctx->keylen); | ||
516 | } | ||
488 | 517 | ||
489 | /* CPU transfer */ | 518 | /* CPU transfer */ |
490 | 519 | ||
@@ -1769,6 +1798,137 @@ static struct aead_alg aes_gcm_alg = { | |||
1769 | }; | 1798 | }; |
1770 | 1799 | ||
1771 | 1800 | ||
1801 | /* xts functions */ | ||
1802 | |||
1803 | static inline struct atmel_aes_xts_ctx * | ||
1804 | atmel_aes_xts_ctx_cast(struct atmel_aes_base_ctx *ctx) | ||
1805 | { | ||
1806 | return container_of(ctx, struct atmel_aes_xts_ctx, base); | ||
1807 | } | ||
1808 | |||
1809 | static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd); | ||
1810 | |||
1811 | static int atmel_aes_xts_start(struct atmel_aes_dev *dd) | ||
1812 | { | ||
1813 | struct atmel_aes_xts_ctx *ctx = atmel_aes_xts_ctx_cast(dd->ctx); | ||
1814 | struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq); | ||
1815 | struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req); | ||
1816 | unsigned long flags; | ||
1817 | int err; | ||
1818 | |||
1819 | atmel_aes_set_mode(dd, rctx); | ||
1820 | |||
1821 | err = atmel_aes_hw_init(dd); | ||
1822 | if (err) | ||
1823 | return atmel_aes_complete(dd, err); | ||
1824 | |||
1825 | /* Compute the tweak value from req->info with ecb(aes). */ | ||
1826 | flags = dd->flags; | ||
1827 | dd->flags &= ~AES_FLAGS_MODE_MASK; | ||
1828 | dd->flags |= (AES_FLAGS_ECB | AES_FLAGS_ENCRYPT); | ||
1829 | atmel_aes_write_ctrl_key(dd, false, NULL, | ||
1830 | ctx->key2, ctx->base.keylen); | ||
1831 | dd->flags = flags; | ||
1832 | |||
1833 | atmel_aes_write_block(dd, AES_IDATAR(0), req->info); | ||
1834 | return atmel_aes_wait_for_data_ready(dd, atmel_aes_xts_process_data); | ||
1835 | } | ||
1836 | |||
1837 | static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd) | ||
1838 | { | ||
1839 | struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq); | ||
1840 | bool use_dma = (req->nbytes >= ATMEL_AES_DMA_THRESHOLD); | ||
1841 | u32 tweak[AES_BLOCK_SIZE / sizeof(u32)]; | ||
1842 | static const u32 one[AES_BLOCK_SIZE / sizeof(u32)] = {cpu_to_le32(1), }; | ||
1843 | u8 *tweak_bytes = (u8 *)tweak; | ||
1844 | int i; | ||
1845 | |||
1846 | /* Read the computed ciphered tweak value. */ | ||
1847 | atmel_aes_read_block(dd, AES_ODATAR(0), tweak); | ||
1848 | /* | ||
1849 | * Hardware quirk: | ||
1850 | * the order of the ciphered tweak bytes need to be reversed before | ||
1851 | * writing them into the ODATARx registers. | ||
1852 | */ | ||
1853 | for (i = 0; i < AES_BLOCK_SIZE/2; ++i) { | ||
1854 | u8 tmp = tweak_bytes[AES_BLOCK_SIZE - 1 - i]; | ||
1855 | |||
1856 | tweak_bytes[AES_BLOCK_SIZE - 1 - i] = tweak_bytes[i]; | ||
1857 | tweak_bytes[i] = tmp; | ||
1858 | } | ||
1859 | |||
1860 | /* Process the data. */ | ||
1861 | atmel_aes_write_ctrl(dd, use_dma, NULL); | ||
1862 | atmel_aes_write_block(dd, AES_TWR(0), tweak); | ||
1863 | atmel_aes_write_block(dd, AES_ALPHAR(0), one); | ||
1864 | if (use_dma) | ||
1865 | return atmel_aes_dma_start(dd, req->src, req->dst, req->nbytes, | ||
1866 | atmel_aes_transfer_complete); | ||
1867 | |||
1868 | return atmel_aes_cpu_start(dd, req->src, req->dst, req->nbytes, | ||
1869 | atmel_aes_transfer_complete); | ||
1870 | } | ||
1871 | |||
1872 | static int atmel_aes_xts_setkey(struct crypto_ablkcipher *tfm, const u8 *key, | ||
1873 | unsigned int keylen) | ||
1874 | { | ||
1875 | struct atmel_aes_xts_ctx *ctx = crypto_ablkcipher_ctx(tfm); | ||
1876 | int err; | ||
1877 | |||
1878 | err = xts_check_key(crypto_ablkcipher_tfm(tfm), key, keylen); | ||
1879 | if (err) | ||
1880 | return err; | ||
1881 | |||
1882 | memcpy(ctx->base.key, key, keylen/2); | ||
1883 | memcpy(ctx->key2, key + keylen/2, keylen/2); | ||
1884 | ctx->base.keylen = keylen/2; | ||
1885 | |||
1886 | return 0; | ||
1887 | } | ||
1888 | |||
1889 | static int atmel_aes_xts_encrypt(struct ablkcipher_request *req) | ||
1890 | { | ||
1891 | return atmel_aes_crypt(req, AES_FLAGS_XTS | AES_FLAGS_ENCRYPT); | ||
1892 | } | ||
1893 | |||
1894 | static int atmel_aes_xts_decrypt(struct ablkcipher_request *req) | ||
1895 | { | ||
1896 | return atmel_aes_crypt(req, AES_FLAGS_XTS); | ||
1897 | } | ||
1898 | |||
1899 | static int atmel_aes_xts_cra_init(struct crypto_tfm *tfm) | ||
1900 | { | ||
1901 | struct atmel_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); | ||
1902 | |||
1903 | tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_aes_reqctx); | ||
1904 | ctx->base.start = atmel_aes_xts_start; | ||
1905 | |||
1906 | return 0; | ||
1907 | } | ||
1908 | |||
1909 | static struct crypto_alg aes_xts_alg = { | ||
1910 | .cra_name = "xts(aes)", | ||
1911 | .cra_driver_name = "atmel-xts-aes", | ||
1912 | .cra_priority = ATMEL_AES_PRIORITY, | ||
1913 | .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, | ||
1914 | .cra_blocksize = AES_BLOCK_SIZE, | ||
1915 | .cra_ctxsize = sizeof(struct atmel_aes_xts_ctx), | ||
1916 | .cra_alignmask = 0xf, | ||
1917 | .cra_type = &crypto_ablkcipher_type, | ||
1918 | .cra_module = THIS_MODULE, | ||
1919 | .cra_init = atmel_aes_xts_cra_init, | ||
1920 | .cra_exit = atmel_aes_cra_exit, | ||
1921 | .cra_u.ablkcipher = { | ||
1922 | .min_keysize = 2 * AES_MIN_KEY_SIZE, | ||
1923 | .max_keysize = 2 * AES_MAX_KEY_SIZE, | ||
1924 | .ivsize = AES_BLOCK_SIZE, | ||
1925 | .setkey = atmel_aes_xts_setkey, | ||
1926 | .encrypt = atmel_aes_xts_encrypt, | ||
1927 | .decrypt = atmel_aes_xts_decrypt, | ||
1928 | } | ||
1929 | }; | ||
1930 | |||
1931 | |||
1772 | /* Probe functions */ | 1932 | /* Probe functions */ |
1773 | 1933 | ||
1774 | static int atmel_aes_buff_init(struct atmel_aes_dev *dd) | 1934 | static int atmel_aes_buff_init(struct atmel_aes_dev *dd) |
@@ -1877,6 +2037,9 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) | |||
1877 | { | 2037 | { |
1878 | int i; | 2038 | int i; |
1879 | 2039 | ||
2040 | if (dd->caps.has_xts) | ||
2041 | crypto_unregister_alg(&aes_xts_alg); | ||
2042 | |||
1880 | if (dd->caps.has_gcm) | 2043 | if (dd->caps.has_gcm) |
1881 | crypto_unregister_aead(&aes_gcm_alg); | 2044 | crypto_unregister_aead(&aes_gcm_alg); |
1882 | 2045 | ||
@@ -1909,8 +2072,16 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) | |||
1909 | goto err_aes_gcm_alg; | 2072 | goto err_aes_gcm_alg; |
1910 | } | 2073 | } |
1911 | 2074 | ||
2075 | if (dd->caps.has_xts) { | ||
2076 | err = crypto_register_alg(&aes_xts_alg); | ||
2077 | if (err) | ||
2078 | goto err_aes_xts_alg; | ||
2079 | } | ||
2080 | |||
1912 | return 0; | 2081 | return 0; |
1913 | 2082 | ||
2083 | err_aes_xts_alg: | ||
2084 | crypto_unregister_aead(&aes_gcm_alg); | ||
1914 | err_aes_gcm_alg: | 2085 | err_aes_gcm_alg: |
1915 | crypto_unregister_alg(&aes_cfb64_alg); | 2086 | crypto_unregister_alg(&aes_cfb64_alg); |
1916 | err_aes_cfb64_alg: | 2087 | err_aes_cfb64_alg: |
@@ -1928,6 +2099,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) | |||
1928 | dd->caps.has_cfb64 = 0; | 2099 | dd->caps.has_cfb64 = 0; |
1929 | dd->caps.has_ctr32 = 0; | 2100 | dd->caps.has_ctr32 = 0; |
1930 | dd->caps.has_gcm = 0; | 2101 | dd->caps.has_gcm = 0; |
2102 | dd->caps.has_xts = 0; | ||
1931 | dd->caps.max_burst_size = 1; | 2103 | dd->caps.max_burst_size = 1; |
1932 | 2104 | ||
1933 | /* keep only major version number */ | 2105 | /* keep only major version number */ |
@@ -1937,6 +2109,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) | |||
1937 | dd->caps.has_cfb64 = 1; | 2109 | dd->caps.has_cfb64 = 1; |
1938 | dd->caps.has_ctr32 = 1; | 2110 | dd->caps.has_ctr32 = 1; |
1939 | dd->caps.has_gcm = 1; | 2111 | dd->caps.has_gcm = 1; |
2112 | dd->caps.has_xts = 1; | ||
1940 | dd->caps.max_burst_size = 4; | 2113 | dd->caps.max_burst_size = 4; |
1941 | break; | 2114 | break; |
1942 | case 0x200: | 2115 | case 0x200: |