| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2020 Metempsy Technology Consulting |
| // All rights reserved |
| // |
| // The license below extends only to copyright in the software and shall |
| // not be construed as granting a license to any other intellectual |
| // property including but not limited to intellectual property relating |
| // to a hardware implementation of the functionality of the software |
| // licensed hereunder. You may use the software subject to the license |
| // terms below provided that you ensure that this notice is replicated |
| // unmodified and in its entirety in all distributions of the software, |
| // modified or unmodified, in source code or in binary form. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer; |
| // redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution; |
| // neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "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 COPYRIGHT |
| // OWNER 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 "arch/arm/qarma.hh" |
| |
| #include <array> |
| |
| #include "base/bitfield.hh" |
| |
| using namespace QARMA; |
| using namespace std; |
| |
| |
| uint8_t |
| QARMA::rotCell(uint8_t incell, int amount) |
| { |
| uint8_t res = ((incell << amount) | (incell >> (4-amount)))& 0xF; |
| return res; |
| } |
| |
| uint8_t |
| QARMA::tweakCellInvRot(uint8_t incell) |
| { |
| uint8_t outcell = 0x0; |
| outcell = incell << 1; |
| uint8_t t = 0x1 & (incell ^ (incell>>3)); |
| outcell |= t; |
| return outcell & 0xF; |
| } |
| |
| uint8_t |
| QARMA::tweakCellRot(uint8_t incell) |
| { |
| uint8_t outcell = 0x0; |
| outcell = incell >> 1; |
| uint8_t t = 0x1 & (incell ^ (incell>>1)); |
| outcell |= t<<3; |
| return outcell & 0xF; |
| } |
| |
| BIT64 |
| QARMA::tweakInvShuffle(BIT64 indata) |
| { |
| BIT64 outdata = 0x0; |
| outdata.b0 = tweakCellInvRot(indata.b12); |
| outdata.b1 = indata.b13; |
| outdata.b2 = indata.b5; |
| outdata.b3 = indata.b6; |
| outdata.b4 = indata.b0; |
| outdata.b5 = indata.b1; |
| outdata.b6 = tweakCellInvRot(indata.b2); |
| outdata.b7 = indata.b3; |
| outdata.b8 = tweakCellInvRot(indata.b7); |
| outdata.b9 = tweakCellInvRot(indata.b15); |
| outdata.b10 = tweakCellInvRot(indata.b14); |
| outdata.b11 = tweakCellInvRot(indata.b4); |
| outdata.b12 = indata.b8; |
| outdata.b13 = indata.b9; |
| outdata.b14 = indata.b10; |
| outdata.b15 = tweakCellInvRot(indata.b11); |
| return outdata; |
| } |
| |
| BIT64 |
| QARMA::tweakShuffle(BIT64 indata) |
| { |
| BIT64 outdata = 0x0; |
| outdata.b0 = indata.b4; |
| outdata.b1 = indata.b5; |
| outdata.b2 = tweakCellRot(indata.b6); |
| outdata.b3 = indata.b7; |
| outdata.b4 = tweakCellRot(indata.b11); |
| outdata.b5 = indata.b2; |
| outdata.b6 = indata.b3; |
| outdata.b7 = tweakCellRot(indata.b8); |
| outdata.b8 = indata.b12; |
| outdata.b9 = indata.b13; |
| outdata.b10 = indata.b14; |
| outdata.b11 = tweakCellRot(indata.b15); |
| outdata.b12 = tweakCellRot(indata.b0); |
| outdata.b13 = indata.b1; |
| outdata.b14 = tweakCellRot(indata.b10); |
| outdata.b15 = tweakCellRot(indata.b9); |
| return outdata; |
| } |
| |
| |
| BIT64 |
| QARMA::PACCellInvShuffle(BIT64 indata) |
| { |
| BIT64 outdata = 0x0; |
| outdata.b0 = indata.b3; |
| outdata.b1 = indata.b6; |
| outdata.b2 = indata.b12; |
| outdata.b3 = indata.b9; |
| outdata.b4 = indata.b14; |
| outdata.b5 = indata.b11; |
| outdata.b6 = indata.b1; |
| outdata.b7 = indata.b4; |
| outdata.b8 = indata.b8; |
| outdata.b9 = indata.b13; |
| outdata.b10 = indata.b7; |
| outdata.b11 = indata.b2; |
| outdata.b12 = indata.b5; |
| outdata.b13 = indata.b0; |
| outdata.b14 = indata.b10; |
| outdata.b15 = indata.b15; |
| return outdata; |
| } |
| |
| BIT64 |
| QARMA::PACCellShuffle(BIT64 indata) |
| { |
| BIT64 outdata = 0x0; |
| outdata.b0 = indata.b13; |
| outdata.b1 = indata.b6; |
| outdata.b2 = indata.b11; |
| outdata.b3 = indata.b0; |
| outdata.b4 = indata.b7; |
| outdata.b5 = indata.b12; |
| outdata.b6 = indata.b1; |
| outdata.b7 = indata.b10; |
| outdata.b8 = indata.b8; |
| outdata.b9 = indata.b3; |
| outdata.b10 = indata.b14; |
| outdata.b11 = indata.b5; |
| outdata.b12 = indata.b2; |
| outdata.b13 = indata.b9; |
| outdata.b14 = indata.b4; |
| outdata.b15 = indata.b15; |
| return outdata; |
| } |
| |
| |
| uint64_t |
| QARMA::PACInvSub(uint64_t tInput) |
| { |
| // This is a 4-bit substitution from the PRINCE-family cipher |
| uint64_t t_output = 0x0; |
| for (int i=15; i>=0; i--) { |
| t_output = t_output << 4; |
| uint8_t b = (tInput >> i*4 ) & 0xF; |
| switch ( b ) { |
| case 0x0: |
| t_output |= 0x5; |
| break; |
| case 0x1: |
| t_output |= 0xe; |
| break; |
| case 0x2: |
| t_output |= 0xd; |
| break; |
| case 0x3: |
| t_output |= 0x8; |
| break; |
| case 0x4: |
| t_output |= 0xa; |
| break; |
| case 0x5: |
| t_output |= 0xb; |
| break; |
| case 0x6: |
| t_output |= 0x1; |
| break; |
| case 0x7: |
| t_output |= 0x9; |
| break; |
| case 0x8: |
| t_output |= 0x2; |
| break; |
| case 0x9: |
| t_output |= 0x6; |
| break; |
| case 0xa: |
| t_output |= 0xf; |
| break; |
| case 0xb: |
| t_output |= 0x0; |
| break; |
| case 0xc: |
| t_output |= 0x4; |
| break; |
| case 0xd: |
| t_output |= 0xc; |
| break; |
| case 0xe: |
| t_output |= 0x7; |
| break; |
| case 0xf: |
| t_output |= 0x3; |
| break; |
| default: |
| //unreachable |
| break; |
| } |
| } |
| return t_output; |
| } |
| |
| uint64_t |
| QARMA::PACSub(uint64_t tInput){ |
| // This is a 4-bit substitution from the PRINCE-family cipher |
| uint64_t t_output = 0x0; |
| for (int i=15; i>=0; i--) { |
| t_output = t_output << 4; |
| uint8_t b = (tInput >> i*4 ) & 0xF; |
| switch ( b ) { |
| case 0x0: |
| t_output |= 0xb; |
| break; |
| case 0x1: |
| t_output |= 0x6; |
| break; |
| case 0x2: |
| t_output |= 0x8; |
| break; |
| case 0x3: |
| t_output |= 0xf; |
| break; |
| case 0x4: |
| t_output |= 0xc; |
| break; |
| case 0x5: |
| t_output |= 0x0; |
| break; |
| case 0x6: |
| t_output |= 0x9; |
| break; |
| case 0x7: |
| t_output |= 0xe; |
| break; |
| case 0x8: |
| t_output |= 0x3; |
| break; |
| case 0x9: |
| t_output |= 0x7; |
| break; |
| case 0xa: |
| t_output |= 0x4; |
| break; |
| case 0xb: |
| t_output |= 0x5; |
| break; |
| case 0xc: |
| t_output |= 0xd; |
| break; |
| case 0xd: |
| t_output |= 0x2; |
| break; |
| case 0xe: |
| t_output |= 0x1; |
| break; |
| case 0xf: |
| t_output |= 0xa; |
| break; |
| default: |
| //unreachable |
| break; |
| } |
| } |
| return t_output; |
| } |
| |
| uint64_t |
| QARMA::PACMult(uint64_t tInput) |
| { |
| uint64_t t_output = 0; |
| |
| for (int i=0;i<=3; i++) { |
| uint8_t b8 = (tInput >> (4*(i+8))) & 0xF; |
| uint8_t b4 = (tInput >> (4*(i+4))) & 0xF; |
| uint8_t b12 = (tInput >> (4*(i+12))) & 0xF; |
| uint8_t b0 = (tInput >> (4*(i))) & 0xF; |
| |
| uint64_t t0 = rotCell(b8, 1) ^ rotCell(b4, 2); |
| t0 = t0 ^ rotCell(b0, 1); |
| |
| uint64_t t1 = rotCell(b12, 1) ^ rotCell(b4, 1); |
| t1 = t1 ^ rotCell(b0, 2); |
| |
| uint64_t t2 = rotCell(b12, 2) ^ rotCell(b8, 1); |
| t2 = t2 ^ rotCell(b0, 1); |
| |
| uint64_t t3 = rotCell(b12, 1) ^ rotCell(b8, 2); |
| t3 = t3 ^ rotCell(b4, 1); |
| |
| t_output |= (t3 << (4*i)); |
| t_output |= (t2 << (4*(i+4))); |
| t_output |= (t1 << (4*(i+8))); |
| t_output |= (t0 << (4*(i+12))); |
| } |
| return t_output; |
| } |
| |
| BIT64 |
| QARMA::computePAC(BIT64 data, BIT64 modifier, BIT64 key0, BIT64 key1) |
| { |
| BIT64 workingval; |
| BIT64 runningmod; |
| BIT64 roundkey; |
| BIT64 modk0; |
| std::array<BIT64, 5> RC; |
| RC[0] = (BIT64) 0x0000000000000000; |
| RC[1] = (BIT64) 0x13198A2E03707344; |
| RC[2] = (BIT64) 0xA4093822299F31D0; |
| RC[3] = (BIT64) 0x082EFA98EC4E6C89; |
| RC[4] = (BIT64) 0x452821E638D01377; |
| |
| const BIT64 alpha = 0xC0AC29B7C97C50DD; |
| //modk0 = key0<0>:key0<63:2>: |
| |
| modk0 = (key0 & 0x1) << 63; |
| modk0 = modk0 | ((key0 & ~0x3) >> 1); |
| modk0 = modk0 | ((key0.b15>>3) ^ ((key0.b0 & 0x2)>>1)); |
| |
| runningmod = modifier; |
| workingval = data^key0; |
| for (int i=0; i<=4; i++) { |
| roundkey = key1 ^ runningmod; |
| workingval = workingval ^ roundkey; |
| workingval = workingval ^ RC[i]; |
| |
| if (i > 0) { |
| workingval = PACCellShuffle(workingval); |
| workingval = PACMult(workingval); |
| } |
| workingval = PACSub(workingval); |
| runningmod = tweakShuffle(runningmod); |
| } |
| roundkey = modk0 ^ runningmod; |
| workingval = workingval ^ roundkey; |
| |
| workingval = PACCellShuffle(workingval); |
| workingval = PACMult(workingval); |
| workingval = PACSub(workingval); |
| workingval = PACCellShuffle(workingval); |
| workingval = PACMult(workingval); |
| workingval = key1 ^ workingval; |
| |
| workingval = PACCellInvShuffle(workingval); |
| workingval = PACInvSub(workingval); |
| workingval = PACMult(workingval); |
| workingval = PACCellInvShuffle(workingval); |
| workingval = workingval ^ key0; |
| workingval = workingval ^ runningmod; |
| |
| for (int i=0; i<=4; i++) { |
| workingval = PACInvSub(workingval); |
| if (i < 4) { |
| workingval = PACMult(workingval); |
| workingval = PACCellInvShuffle(workingval); |
| } |
| runningmod = tweakInvShuffle(runningmod); |
| roundkey = key1 ^ runningmod; |
| workingval = workingval ^ RC[4-i]; |
| workingval = workingval ^ roundkey; |
| workingval = workingval ^ alpha; |
| } |
| workingval = workingval ^ modk0; |
| return workingval; |
| } |
| |