/** * encrypt.c * * @version 1.0 (March 2019) * * Reference ANSI C code for the Qameleon memory encryption cipher * * @author Roberto Avanzi , * @author Subhadeep Banik * @author Francesco Regazzoni * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "api.h" #include "crypto_aead.h" #include #include #include #include "qarma128_11.h" #define MSB_AD (0x2<<4) #define MSB_AD_LAST (0x3<<4) #define MSB_M (0x0<<4) #define MSB_MB (0x8<<4) #define MSB_NE (0xF<<4) #define MSB_LAST (0x1<<4) #define MSB_LASTB (0x9<<4) #define MSB_CHKSUM (0x4<<4) #define MSB_CHKSUMB (0xC<<4) #define ROUNDS 11 #define TAGLENGTH 8 void set_nonce_in_tweak(u8 * tweak, const u8 * nonce) { tweak[0] = (tweak[0] & 0xf0) ^ (nonce[0] >> 4); tweak[1] = (nonce[0] & 0xf) << 4 ^ (nonce[1] >> 4); tweak[2] = (nonce[1] & 0xf) << 4 ^ (nonce[2] >> 4); tweak[3] = (nonce[2] & 0xf) << 4 ^ (nonce[3] >> 4); tweak[4] = (nonce[3] & 0xf) << 4 ^ (nonce[4] >> 4); tweak[5] = (nonce[4] & 0xf) << 4 ^ (nonce[5] >> 4); tweak[6] = (nonce[5] & 0xf) << 4 ^ (nonce[6] >> 4); tweak[7] = (nonce[6] & 0xf) << 4 ^ (nonce[7] >> 4); tweak[8] = (nonce[7] & 0xf) << 4; } /* * * Modifiy the block number in the tweak value */ void set_block_number_in_tweak(u8 * tweak, const u64 block_no) { tweak[8] = (tweak[8] & 0xf0) ^ ((block_no >> 56ULL) & 0xf); tweak[9] = ((block_no >> 48ULL) & 0xff); tweak[10] = ((block_no >> 40ULL) & 0xff); tweak[11] = ((block_no >> 32ULL) & 0xff); tweak[12] = ((block_no >> 24ULL) & 0xff); tweak[13] = ((block_no >> 16ULL) & 0xff); tweak[14] = ((block_no >> 8ULL) & 0xff); tweak[15] = ((block_no >> 0ULL) & 0xff); } /* * * Modifiy the stage value in the tweak value */ void set_stage_in_tweak(u8 * tweak, const u8 value) { tweak[0] = (tweak[0] & 0xf) ^ value; } 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 ) { unsigned long long int i; unsigned long long int j; unsigned char tweak[16], k0[16], w0[16], k1[16], k1_M[16], w1[16]; unsigned char last_block[16]; unsigned char Checksum[16]; unsigned char Final[16]; unsigned char Pad[16]; (void)nsec; (void)ad; if (adlen != 0) return -1; for (i = 0; i < 16; i++) { w0[i] = k[i]; k0[i] = k[16 + i]; } for (i = 0; i < mlen + TAGLENGTH; i++) { c[i] = 0; } *clen = 0; for (j = 0; j < 16; j++) Checksum[j] = 0; KeySpecialisation(k0, w0, k1, k1_M, w1); for (j = 0; j < 16; j++) tweak[j] = 0; if (mlen) { /* Message */ for (j = 0; j < 16; j++) tweak[j] = 0; set_nonce_in_tweak(tweak, npub); set_stage_in_tweak(tweak, MSB_M); i = 0; while (16 * (i + 1) < mlen) { for (j = 0; j < 16; j++) Checksum[j] ^= m[16 * i + j]; set_block_number_in_tweak(tweak, i); qarma128(m + 16 * i, w0, w1, k0, k1, tweak, ROUNDS, c + 16 * i); i++; } /* Process last block */ for (j = 0; j < 16; j++) last_block[j] = 0; for (j = 0; j < mlen - 16 * i; j++) last_block[j] = *(m + 16 * i + j); //xor_values(Checksum, last_block); for (j = 0; j < 16; j++) Checksum[j] ^= last_block[j]; /* Encrypt it */ set_stage_in_tweak(tweak, MSB_LAST); set_block_number_in_tweak(tweak, mlen); qarma128(last_block, w0, w1, k0, k1, tweak, ROUNDS, Pad); /* Write the ciphertext block */ for (j = 0; j < 16; j++) { c[16 * i + j] = Pad[j]; } *clen = 16 * i + 16; } /* if message length>0 */ set_stage_in_tweak(tweak, MSB_CHKSUM); set_nonce_in_tweak(tweak, npub); set_block_number_in_tweak(tweak, 0); qarma128(Checksum, w0, w1, k0, k1, tweak, ROUNDS, Final); for (i = 0; i < TAGLENGTH; i++) { c[*clen + i] = Final[i]; } *clen = *clen + TAGLENGTH; return 0; } int crypto_aead_decrypt( unsigned char *m, unsigned long long *outputmlen, unsigned char *nsec, const unsigned char *c, unsigned long long clen, const unsigned char *ad, unsigned long long adlen, const unsigned char *npub, const unsigned char *k ) { unsigned char tweak[16], k0[16], w0[16], k1[16], k1_M[16], w1[16], w0d [16], k0d[16], w1d[16]; unsigned long long int i; unsigned long long int j; unsigned char Checksum[16]; unsigned char Final[16]; unsigned char Pad[16]; unsigned char Tag[TAGLENGTH], Tagc[TAGLENGTH]; (void)nsec; (void)ad; if (adlen != 0) return -1; if (clen % 64 != TAGLENGTH) return -1; for (i = 0; i < 16; i++) { w0[i] = k[i]; k0[i] = k[16 + i]; } KeySpecialisation_dec(k0, w0, k1, k1_M, w1, w0d, w1d, k0d); /* Get the tag from the last 16 bytes of the ciphertext */ memcpy(Tag, c + clen - TAGLENGTH, TAGLENGTH); /* * Update c_len to the actual size of the ciphertext (i.e., without * the tag) */ *outputmlen = clen - TAGLENGTH; clen -= TAGLENGTH; /* Fill the tweak from nonce */ memset(tweak, 0, 16); for (j = 0; j < 16; j++) Checksum[j] = 0; i = 0; if (clen) { /* Message */ for (j = 0; j < 16; j++) tweak[j] = 0; set_nonce_in_tweak(tweak, npub); set_stage_in_tweak(tweak, MSB_M); i = 0; while (16 * (i + 1) < clen) { set_block_number_in_tweak(tweak, i); qarma128(c + 16 * i, w0d, w1d, k0d, k1_M, tweak, ROUNDS, m + 16 * i); for (j = 0; j < 16; j++) Checksum[j] ^= m[16 * i + j]; i++; } /* Process last block */ /* Encrypt it */ set_stage_in_tweak(tweak, MSB_LAST); set_block_number_in_tweak(tweak, *outputmlen); qarma128(c + 16 * i, w0d, w1d, k0d, k1_M, tweak, ROUNDS, Pad); for (j = 0; j < 16; j++) Checksum[j] ^= Pad[j]; /* Write the ciphertext block */ for (j = 0; j < *outputmlen - 16 * i; j++) { m[16 * i + j] = Pad[j]; } } /* if message length>0 */ set_stage_in_tweak(tweak, MSB_CHKSUM); set_nonce_in_tweak(tweak, npub); set_block_number_in_tweak(tweak, 0); qarma128(Checksum, w0, w1, k0, k1, tweak, ROUNDS, Final); for (j = 0; j < TAGLENGTH; j++) Tagc[j] = Final[j]; if (0 != memcmp(Tagc, Tag, TAGLENGTH)) { memset(m, 0, clen); return -1; } return 0; }