Is it possible to add block ciphers for Cavium octeon

Thanks, it was easy work😃

But are you surprised? If OpenWRT with all its lines of code have this forum with all the people doing murphy law things with the firmware.
How can a 5000lines of security code survive the dangerous real life world outside the programmers nice clean lab where people start the work process to give the program a big blow with a big sledgehammer and then say it doesn’t work.

This is basic programming know-how. To write what you want to do require probably 5000lines of code. But to write what it shouldn’t do in all Murphy’s law eventualities while doing the best 5k lines of code takes 100000 additional lines of code.
Don’t be surprised if Wireguard as everyone else also has 105000lines of code in 10years.

Why do you think OpenVPN has 100000lines of code in the first place?

btw. the dd-wrt openssl version contains a modification for octeon aes/des/md5 acceleration in userspace (no cryptodev involved). its implemented using the special hw crypto assembly for octeon cpus and it works on ubnt edge routers (tested edgepro and edgelite)

1 Like

Thanks for maintaining the dd-wrt! I may try this openssl in openwrt. I have two questions:

  1. Seems that gcm is not support in your openssl. Do you have a plan to implement it?
  2. I really want to use octeon hw acceleration in kernel space, so IPSec and opvp-dco[1] can benefit from it a lot. Will you also implement this? Some hash algs have been implemented in latest kernel [2].

[1] https://github.com/OpenVPN/ovpn-dco
[2]https://elixir.bootlin.com/linux/latest/source/arch/mips/cavium-octeon/crypto

its not yet supported since i'm missing some code documentation. i know that wolfssl contains some code pieces for aes-gcm. right now i'm working on the crypto kernel modules. my work on openssl has been done many years ago. for the kernel i fixed some endian issues if you boot the kernel in little endian mode and i added aes and aes-cbc so far in the last days (you can find it in my 4.9 kernel tree. but its easy portable to 6.1. i havent done my work yet for the latest kernel on the edgerouter. but on the other hands i backported ovpn-dco to older kernels till 4.4 :slight_smile:

for aes etc kernel modules watch here

It's great to see that ovpn-dco is backported to older kernels because someone like me also need to stay in the older kernel because of some reasons.Please ping me if you want me to test or debug when the aes-gcm kernel module is ready. I will test it with ovpn-dco.

depending on my mood i think i can finish the gcm aes within the next days. but consider that the in kernel ghash module combined with the aes hw crypto module which i just added does already bring hw accelleration to gcm aes, just not for the ghash part

i wrote now also a ghash module for octeon hw crypto. so technically gcm(aes) is now hw accellerated. a combined gcm(aes) might come soon. i'm currently struggeling with the kernel crypto api. too many crashes today while working on this. need some break

1 Like

Thanks. I have been watching your code.

gcm(aes) is now finished and tested. (kernel internal crypto tests only so far)

Thanks for the update. I will try it and feedback.

any results? btw: i wrote now also a module for crc32 and crc32c acceleration

I finished porting kernel module to openwrt two days ago, but have not tested yet because one urgent thing to do in my work. Will test soon. Thanks for crc acceleration.

converting them to skcipher shouldnt be that hard. one of the modules (the gcm aes) is already compatible with newer kernels since it makes use of the newer skcipher api which i backported to 4.9.

sorry for the late feedback. I tested with ovpn-dco. It doesn't work in my env. Here is the log.

2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_TCPNL=1
2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_MTU=1600
2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_NCP=2
2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_CIPHERS=AES-256-GCM:AES-128-GCM
2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_PROTO=990
2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_GUI_VER=OpenVPN_GUI_11.46.0.0
2024-01-10 07:11:10 192.168.5.226:61949 peer info: IV_SSO=openurl,webauth,crtext
2024-01-10 07:11:10 192.168.5.226:61949 TLS: move_session: dest=TM_ACTIVE src=TM_INITIAL reinit_src=1
2024-01-10 07:11:10 192.168.5.226:61949 TLS: tls_multi_process: initial untrusted session promoted to trusted
2024-01-10 07:11:10 192.168.5.226:61949 Control Channel: TLSv1.3, cipher TLSv1.3 TLS_CHACHA20_POLY1305_SHA256, peer certificate: 1024 bits RSA, signature: RSA-SHA256, peer temporary key: 253 bits X9
2024-01-10 07:11:10 192.168.5.226:61949 [client] Peer Connection Initiated with [AF_INET]192.168.5.226:61949
2024-01-10 07:11:10 MULTI: new connection by client 'client' will cause previous active sessions by this client to be dropped.  Remember to use the --duplicate-cn option if you want multiple client.
2024-01-10 07:11:10 MULTI_sva: pool returned IPv4=10.8.0.4, IPv6=(Not enabled)
2024-01-10 07:11:10 MULTI: Learn: 10.8.0.4 -> client/192.168.5.226:61949
2024-01-10 07:11:10 MULTI: primary virtual IP for client/192.168.5.226:61949: 10.8.0.4
2024-01-10 07:11:10 SENT CONTROL [client]: 'PUSH_REPLY,route-gateway 10.8.0.1,topology subnet,ping 10,ping-restart 120,ifconfig 10.8.0.4 255.255.255.0,peer-id 1,cipher AES-256-GCM,protocol-flags cc)
2024-01-10 07:11:11 client/192.168.5.226:61949 Data Channel: cipher 'AES-256-GCM', peer-id: 0
2024-01-10 07:11:11 client/192.168.5.226:61949 Timers: ping 10, ping-restart 240
2024-01-10 07:11:11 client/192.168.5.226:61949 Protocol options: protocol-flags cc-exit tls-ekm dyn-tls-crypt
[10747.047884] ovpn_aead_decrypt: decrypt failed: -77
[10747.052724] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10747.060138] ovpn_aead_decrypt: decrypt failed: -77
[10747.064936] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10748.066469] ovpn_aead_decrypt: decrypt failed: -77
[10748.071321] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10748.078694] ovpn_aead_decrypt: decrypt failed: -77
[10748.083493] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10749.066039] ovpn_aead_decrypt: decrypt failed: -77
[10749.070842] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10760.158441] net_ratelimit: 6 callbacks suppressed
[10760.158445] ovpn_aead_decrypt: decrypt failed: -77
[10760.167971] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10770.159501] ovpn_aead_decrypt: decrypt failed: -77
[10770.164305] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10780.159808] ovpn_aead_decrypt: decrypt failed: -77
[10780.164613] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10790.160776] ovpn_aead_decrypt: decrypt failed: -77
[10790.165582] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10800.191911] ovpn_aead_decrypt: decrypt failed: -77
[10800.196730] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10810.208033] ovpn_aead_decrypt: decrypt failed: -77
[10810.212838] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10820.224335] ovpn_aead_decrypt: decrypt failed: -77
[10820.229154] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10830.224972] ovpn_aead_decrypt: decrypt failed: -77
[10830.229797] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10840.227582] ovpn_aead_decrypt: decrypt failed: -77
[10840.232387] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10850.241868] ovpn_aead_decrypt: decrypt failed: -77
[10850.246674] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10860.257169] ovpn_aead_decrypt: decrypt failed: -77
[10860.261974] ovpn_decrypt_one: error during decryption for peer 1, key-id 0: -77
[10865.697751] tun0: ovpn_udp_encap_recv: control packet from unknown peer, sending to userspace
[10865.698382] tun0: ovpn_udp_encap_recv: control packet from unknown peer, sending to userspace
[10865.713115] tun0: ovpn_udp_encap_recv: control packet from unknown peer, sending to userspace
[10865.721704] tun0: ovpn_udp_encap_recv: control packet from unknown peer, sending to userspace
[10865.730268] tun0: ovpn_udp_encap_recv: control packet from unknown peer, sending to userspace
[10865.738824] tun0: ovpn_udp_encap_recv: control packet from unknown peer, sending to userspace

I use Marvel octeon kernel [1] which is based on 4.14 . The ovpn-dco is from your dd-wrt repo and I also change some code in ovpn-dco and Marvel octeon kernel to make ovpn-dco compiled. I'm not sure if your octeon aes-gcm module introduces this issue for now . Maybe it's my mistake . Will debug. Have you tried the aes-gcm module with ovpn-dco or ipsec?

BTW, the code of octeon aes-gcm I use was fetched about on 2024/1/2 from your repo. I will also use the latest one to have a try.

[1]https://github.com/MarvellEmbeddedProcessors/Octeon-Linux-kernel-4.14

the best is if you start with testing crypto modules by using the kernel embedded testing modules like tcrypt etc. this is how i managed it and i was successfull

in addition you need to fix "control packet from unknown peer" this is something i fixed in my ovpn-dco and it was related to atomic functions if i remember correct

in addition it might be usefull to test ovpn-dco without hw crypto first to make sure that ovpn isnt the problem here

I tried this, it works. I will try to update the code of your aes-gcm module and test again with hw crypto.

As I said before, I'm using your ovpn-dco with minor changes for compiling issues. I believe if you fixed "control packet from unknown peer" issue, the fix is also included in my buildroot.

then its curious why i see this message. but of course i'm using 4.9 on octeon and my kernel is everything else but vanilla. try the tcrypt test module (CONFIG_CRYPTO_TEST=y) first to make sure that the internal crypto tests do not fail. also disable the option "CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y" which is enabled by default

with the tcrypt module you can check all algorithms manually for correct results. but its bad documented. you need to read the code to find out how to use it

I just updated aes-gcm module and diff, seems that I did not remember correct date or we are in different time zone. I mean my original code was not fetched on 2023/01/02. Now it works. I will test the performance to confirm the hw crypto really works. May compare with sw crypto.

#include <asm/octeon/octeon.h>
 #include "octeon-crypto.h"

-MODULE_DESCRIPTION("GHASH & AES-GCM using Octeon HW Crypto");
-MODULE_AUTHOR("Sebastian Gottschall <s.gottschall@dd-wrt.com>");
-MODULE_LICENSE("GPL v2");

 #define GHASH_BLOCK_SIZE       16
 #define GHASH_DIGEST_SIZE      16
@@ -53,7 +50,7 @@
        return 0;
 }

-static void ghash_do_update(int blocks, u64 dg[], const char *src, struct ghash_key *key, const char *head)
+static __always_inline void ghash_do_update(int blocks, u64 dg[], const char *src, struct ghash_key *key, const char *head)
 {
        write_octeon_64bit_gfm_poly((uint64_t) 0xe100);
        write_octeon_64bit_gfm_resinp(dg[0], 0);
@@ -169,7 +166,7 @@
        .descsize = sizeof(struct ghash_desc_ctx),
 };

-static void __octeon_aes_encrypt(u32 *rk, u8 *out, u8 *in, u32 keylen)
+static __always_inline void __octeon_aes_encrypt(u32 *rk, u8 *out, u8 *in, u32 keylen)
 {
        __be64 *dataout = (__be64 *)out;
        __be64 *data = (__be64 *)in;
@@ -178,7 +175,7 @@
        write_octeon_64bit_aes_key(key[1], 1);
        write_octeon_64bit_aes_key(key[2], 2);
        write_octeon_64bit_aes_key(key[3], 3);
-       write_octeon_64bit_aes_keylength(keylen / 8 - 1);
+       write_octeon_64bit_aes_keylength(keylen);
        write_octeon_64bit_aes_enc0(*data++);
        write_octeon_64bit_aes_enc1(*data);
        *dataout++ = read_octeon_64bit_aes_result(0);
@@ -191,19 +188,21 @@
        unsigned long flags;
        struct gcm_aes_ctx *ctx = crypto_aead_ctx(tfm);
        u8 key[GHASH_BLOCK_SIZE];
-       int ret;
-
+       int ret,i;
        ret = crypto_aes_expand_key(&ctx->aes_key, inkey, keylen);
        if (ret) {
                tfm->base.crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
                return -EINVAL;
        }
-
+       for (i=0;i<ctx->aes_key.key_length / 4;i++)
+               ctx->aes_key.key_enc[i] = cpu_to_le32(ctx->aes_key.key_enc[i]);
+       ctx->aes_key.key_length = ctx->aes_key.key_length / 8 - 1;
        flags = octeon_crypto_enable(&state);
        __octeon_aes_encrypt(ctx->aes_key.key_enc, key, (u8[AES_BLOCK_SIZE]) { },
                             ctx->aes_key.key_length);
        octeon_crypto_disable(&state, flags);

+
        return __ghash_setkey(&ctx->ghash_key, key, sizeof(be128));
 }
 }

@@ -287,7 +286,6 @@
 {
        u8 mac[AES_BLOCK_SIZE];
        u128 lengths;
-
        lengths.a = cpu_to_be64(req->assoclen * 8);
        lengths.b = cpu_to_be64(cryptlen * 8);

@@ -314,7 +312,7 @@
        if (req->assoclen)
                gcm_calculate_auth_mac(req, dg);

-       memcpy(iv, req->iv, GCM_IV_SIZE);
+       memcpy(iv, req->iv, GCM_IV_SIZE);
        put_unaligned_be32(1, iv + GCM_IV_SIZE);

        err = skcipher_walk_aead_encrypt(&walk, req, false);
@@ -327,7 +325,6 @@
                u8 *dst = walk.dst.virt.addr;
                u8 *src = walk.src.virt.addr;
                int remaining = blocks;
-
                do {
                        __octeon_aes_encrypt(ctx->aes_key.key_enc, ks, iv, ctx->aes_key.key_length);
                        crypto_xor_cpy(dst, src, ks, AES_BLOCK_SIZE);
@@ -341,20 +338,17 @@

                err = skcipher_walk_done(&walk, walk.nbytes % (2 * AES_BLOCK_SIZE));
        }
-       if (walk.nbytes) {
-               __octeon_aes_encrypt(ctx->aes_key.key_enc, ks, iv, ctx->aes_key.key_length);
-               if (walk.nbytes > AES_BLOCK_SIZE) {
-                       crypto_inc(iv, AES_BLOCK_SIZE);
-                       __octeon_aes_encrypt(ctx->aes_key.key_enc, ks + AES_BLOCK_SIZE, iv, ctx->aes_key.key_length);
-               }
-       }

-       /* handle the tail */
        if (walk.nbytes) {
                u8 buf[GHASH_BLOCK_SIZE];
                unsigned int nbytes = walk.nbytes;
                u8 *dst = walk.dst.virt.addr;
                u8 *head = NULL;
+               __octeon_aes_encrypt(ctx->aes_key.key_enc, ks, iv, ctx->aes_key.key_length);
+               if (walk.nbytes > AES_BLOCK_SIZE) {
+                       crypto_inc(iv, AES_BLOCK_SIZE);
+                       __octeon_aes_encrypt(ctx->aes_key.key_enc, ks + AES_BLOCK_SIZE, iv, ctx->aes_key.key_length);
+               }

                crypto_xor_cpy(walk.dst.virt.addr, walk.src.virt.addr, ks, walk.nbytes);

@@ -428,6 +422,9 @@
                err = skcipher_walk_done(&walk, walk.nbytes % (2 * AES_BLOCK_SIZE));
        }
        if (walk.nbytes) {
+               const u8 *src = walk.src.virt.addr;
+               const u8 *head = NULL;
+               unsigned int nbytes = walk.nbytes;
if (walk.nbytes > AES_BLOCK_SIZE) {
                        u8 *iv2 = iv + AES_BLOCK_SIZE;

@@ -437,13 +434,6 @@
                        __octeon_aes_encrypt(ctx->aes_key.key_enc, iv2, iv2, ctx->aes_key.key_length);
                }
                __octeon_aes_encrypt(ctx->aes_key.key_enc, iv, iv, ctx->aes_key.key_length);
-       }
-
-       /* handle the tail */
-       if (walk.nbytes) {
-               const u8 *src = walk.src.virt.addr;
-               const u8 *head = NULL;
-               unsigned int nbytes = walk.nbytes;

                if (walk.nbytes > GHASH_BLOCK_SIZE) {
                        head = src;
@@ -516,3 +506,7 @@

 module_init(ghash_ce_mod_init);
 module_exit(ghash_ce_mod_exit);
+
+MODULE_DESCRIPTION("GHASH & AES-GCM using Octeon HW Crypto");
+MODULE_AUTHOR("Sebastian Gottschall <s.gottschall@dd-wrt.com>");
+MODULE_LICENSE("GPL v2");

then it was maybe work in progress. i can remember that i finished the first version at 29.12. which worked in my tests. the last version is just a enhancements but i tested that too. now that it works. how is the performance? consider that my ovpn-dco module also supports aes-cbc ccm-aes etc. especially aes-cbc should be the fastest due the way its implemented