#include "skinny128.h" #include "tk_schedule.h" #include "romulus.h" #include "domain.h" #include #include //Encryption and authentication using Romulus-N1 int crypto_aead_encrypt (unsigned char *c, unsigned long long *clen, const unsigned char *m, unsigned long long mlen, const unsigned char *ad, unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k) { u32 tmp; u64 tmp_mlen = mlen; const u8* m_auth = m; u8 final_domain = 0x30; skinny_128_384_tks tks; u8 state[BLOCKBYTES], pad[BLOCKBYTES]; (void)nsec; // ----------------- Initialization ----------------- *clen = mlen + TAGBYTES; memset(tks.tk1, 0x00, KEYBYTES); memset(state, 0x00, BLOCKBYTES); tks.tk1[0] = 0x01; // Init the 56-bit LFSR counter // ----------------- Initialization ----------------- // ----------------- Process the associated data ----------------- final_domain ^= final_ad_domain(adlen, mlen); SET_DOMAIN(tks, 0x28); while (adlen > 2*BLOCKBYTES) { // Process double blocks but the last UPDATE_CTR(tks.tk1); XOR_BLOCK(state, state, ad); precompute_rtk2_3(tks.rtk2_3, npub, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); UPDATE_CTR(tks.tk1); ad += 2*BLOCKBYTES; adlen -= 2*BLOCKBYTES; } // Pad and process the left-over blocks if (adlen == 2*BLOCKBYTES) { // Left-over complete double block UPDATE_CTR(tks.tk1); XOR_BLOCK(state, state, ad); precompute_rtk2_3(tks.rtk2_3, ad + BLOCKBYTES, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); UPDATE_CTR(tks.tk1); } else if (adlen > BLOCKBYTES) { // Left-over partial double block adlen -= BLOCKBYTES; UPDATE_CTR(tks.tk1); XOR_BLOCK(state, state, ad); memcpy(pad, ad + BLOCKBYTES, adlen); memset(pad + adlen, 0x00, 15 - adlen); pad[15] = adlen; // Padding precompute_rtk2_3(tks.rtk2_3, pad, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); UPDATE_CTR(tks.tk1); } else { SET_DOMAIN(tks, 0x2C); UPDATE_CTR(tks.tk1); if (adlen == BLOCKBYTES) { // Left-over complete single block XOR_BLOCK(state, state, ad); } else { // Left-over partial single block for(int i =0; i < (int)adlen; i++) state[i] ^= ad[i]; state[15] ^= adlen; // Padding } if (tmp_mlen >= BLOCKBYTES) { precompute_rtk2_3(tks.rtk2_3, m_auth, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); m_auth += BLOCKBYTES; tmp_mlen -= BLOCKBYTES; if (tmp_mlen > BLOCKBYTES) { UPDATE_CTR(tks.tk1); } } else { memcpy(pad, m_auth, tmp_mlen); memset(pad + tmp_mlen, 0x00, BLOCKBYTES - tmp_mlen - 1); pad[15] = (u8)tmp_mlen; // Padding precompute_rtk2_3(tks.rtk2_3, pad, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); tmp_mlen = 0; } } // Process all message double blocks except the last SET_DOMAIN(tks, 0x2C); while (tmp_mlen > 32) { UPDATE_CTR(tks.tk1); XOR_BLOCK(state, state, m_auth); precompute_rtk2_3(tks.rtk2_3, m_auth + BLOCKBYTES, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); UPDATE_CTR(tks.tk1); m_auth += 2 * BLOCKBYTES; tmp_mlen -= 2 * BLOCKBYTES; } // Process the last message double block if (tmp_mlen == 2 * BLOCKBYTES) { // Last message double block is full UPDATE_CTR(tks.tk1); XOR_BLOCK(state, state, m_auth); precompute_rtk2_3(tks.rtk2_3, m_auth + BLOCKBYTES, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); } else if (tmp_mlen > BLOCKBYTES) { // Last message double block is partial tmp_mlen -= BLOCKBYTES; UPDATE_CTR(tks.tk1); XOR_BLOCK(state, state, m_auth); memcpy(pad, m_auth + BLOCKBYTES, tmp_mlen); memset(pad + tmp_mlen, 0x00, BLOCKBYTES - tmp_mlen - 1); pad[15] = (u8)tmp_mlen; // Padding precompute_rtk2_3(tks.rtk2_3, pad, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); } else if (tmp_mlen == BLOCKBYTES) { // Last message single block is full XOR_BLOCK(state, state, m_auth); } else if (tmp_mlen > 0) { // Last message single block is partial for(int i =0; i < (int)tmp_mlen; i++) state[i] ^= m_auth[i]; state[15] ^= (u8)tmp_mlen; // Padding } // Process the last partial block SET_DOMAIN(tks, final_domain); UPDATE_CTR(tks.tk1); precompute_rtk2_3(tks.rtk2_3, npub, k); precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); // ----------------- Process the associated data ----------------- // ----------------- Generate the tag ----------------- G(state,state); memcpy(c + mlen, state, TAGBYTES); // ----------------- Generate the tag ----------------- memset(tks.tk1, 0x00, KEYBYTES); tks.tk1[0] = 0x01; // Init the 56-bit LFSR counter if (mlen > 0) { SET_DOMAIN(tks, 0x24); while (mlen > BLOCKBYTES) { precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); RHO(state,c,m); UPDATE_CTR(tks.tk1); c += BLOCKBYTES; m += BLOCKBYTES; mlen -= BLOCKBYTES; } precompute_rtk1(tks.rtk1, tks.tk1); skinny128_384_plus(state, state, tks.rtk1, tks.rtk2_3); for(int i = 0; i < (int)mlen; i++) { tmp = m[i]; // Use of tmp variable in case c = m c[i] = m[i] ^ (state[i] >> 1) ^ (state[i] & 0x80) ^ (state[i] << 7); state[i] ^= (u8)tmp; } state[15] ^= (u8)mlen; // Padding } return 0; }