1 // 2 // Copyright (c) 2010-2021 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using Antmicro.Renode.Utilities; 9 10 namespace Antmicro.Renode.Utilities 11 { 12 public class PRESENTCipher 13 { 14 // For cryptographic purposes use provided constants, more info: https://link.springer.com/content/pdf/10.1007%2F978-3-540-74735-2_31.pdf 15 // Note that current implementation assumes 64-bit `key`, but could be extended to 80-bit or 128-bit in the future. 16 Scramble(ulong data, ulong key, int width = OriginalDataWidth, uint rounds = OriginalNumberOfRounds)17 static public ulong Scramble(ulong data, ulong key, int width = OriginalDataWidth, uint rounds = OriginalNumberOfRounds) 18 { 19 if(width < 0 || width > 64) 20 { 21 throw new ArgumentException($"{width} is out of bounds [0, 64]", "width"); 22 } 23 if(data > (ulong.MaxValue >> (64 - width))) 24 { 25 throw new ArgumentException($"0x{data:X} doesn't fit in width ({width}) bits", "data"); 26 } 27 28 var state = data; 29 for(var i = 0; i < rounds; ++i) 30 { 31 state ^= key; 32 state = Substitute(state, width, coefficientsForward); 33 state = Permutate(state, width); 34 } 35 36 return state ^ key; 37 } 38 Descramble(ulong data, ulong key, int width = OriginalDataWidth, uint rounds = OriginalNumberOfRounds)39 static public ulong Descramble(ulong data, ulong key, int width = OriginalDataWidth, uint rounds = OriginalNumberOfRounds) 40 { 41 if(width < 0 || width > 64) 42 { 43 throw new ArgumentException($"{width} is out of bounds [0, 64]", "width"); 44 } 45 if(data > (ulong.MaxValue >> (64 - width))) 46 { 47 throw new ArgumentException($"0x{data:X} doesn't fit in width ({width}) bits", "data"); 48 } 49 50 var state = data; 51 for(var i = 0; i < rounds; ++i) 52 { 53 state ^= key; 54 state = ReversePermutate(state, width); 55 state = Substitute(state, width, coefficientsReverse); 56 } 57 58 return state ^ key; 59 } 60 Substitute(ulong data, int width, ulong[] coefficients)61 static private ulong Substitute(ulong data, int width, ulong[] coefficients) 62 { 63 var mask = ulong.MaxValue >> (64 - width); 64 var substitutionMask = ulong.MaxValue >> (64 - (width & ~0x3)); 65 66 var state = data & (mask & ~substitutionMask); 67 for(int i = 0; i < width / 4; ++i) 68 { 69 var shift = i * 4; 70 state |= coefficients[(data >> shift) & 0xf] << shift; 71 } 72 73 return state; 74 } 75 Permutate(ulong data, int width)76 static private ulong Permutate(ulong data, int width) 77 { 78 var mask = ulong.MaxValue >> (64 - width); 79 var permutationMask = ulong.MaxValue >> (64 - (width & ~0x1)); 80 81 var reversedData = BitHelper.ReverseBits(data << (64 - width)); 82 var state = reversedData & (mask & ~permutationMask); 83 for(byte j = 0; j < width / 2; ++j) 84 { 85 BitHelper.SetBit(ref state, j, BitHelper.IsBitSet(reversedData, (byte)(2 * j))); 86 BitHelper.SetBit(ref state, (byte)(width / 2 + j), BitHelper.IsBitSet(reversedData, (byte)(2 * j + 1))); 87 } 88 89 return state; 90 } 91 ReversePermutate(ulong data, int width)92 static private ulong ReversePermutate(ulong data, int width) 93 { 94 var mask = ulong.MaxValue >> (64 - width); 95 var permutationMask = ulong.MaxValue >> (64 - (width & ~0x1)); 96 97 var state = data & (mask & ~permutationMask); 98 for(byte j = 0; j < width / 2; ++j) 99 { 100 BitHelper.SetBit(ref state, (byte)(2 * j), BitHelper.IsBitSet(data, j)); 101 BitHelper.SetBit(ref state, (byte)(2 * j + 1), BitHelper.IsBitSet(data, (byte)(width / 2 + j))); 102 } 103 104 return BitHelper.ReverseBits(state << (64 - width)); 105 } 106 107 private static readonly ulong[] coefficientsForward = new ulong[] 108 { 109 0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 110 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2 111 }; 112 113 private static readonly ulong[] coefficientsReverse = new ulong[] 114 { 115 0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd, 116 0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa 117 }; 118 119 private const int OriginalDataWidth = 64; 120 private const uint OriginalNumberOfRounds = 31; 121 } 122 } 123