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 System.Security.Cryptography; 9 10 namespace Antmicro.Renode.Utilities.Crypto 11 { 12 public class AesProvider : IDisposable 13 { GetCbcMacProvider(byte[] key)14 public static AesProvider GetCbcMacProvider(byte[] key) 15 { 16 // CBC-MAC is just CBC with empty IV (all zeros) 17 return new AesProvider(CipherMode.CBC, PaddingMode.Zeros, key, new byte[AesBlockSizeInBytes]); 18 } 19 GetEcbProvider(byte[] key)20 public static AesProvider GetEcbProvider(byte[] key) 21 { 22 // ECB does not use IV at all 23 return new AesProvider(CipherMode.ECB, PaddingMode.Zeros, key); 24 } 25 GetCbcProvider(byte[] key, byte[] iv)26 public static AesProvider GetCbcProvider(byte[] key, byte[] iv) 27 { 28 return new AesProvider(CipherMode.CBC, PaddingMode.None, key, iv); 29 } 30 AesProvider(CipherMode mode, PaddingMode padding, byte[] key, byte[] iv = null)31 public AesProvider(CipherMode mode, PaddingMode padding, byte[] key, byte[] iv = null) 32 { 33 aesEngine = Aes.Create(); 34 aesEngine.Mode = mode; 35 aesEngine.Padding = padding; 36 lastBlock = Block.OfSize(AesBlockSizeInBytes); 37 38 this.key = key; 39 this.iv = iv; 40 } 41 Dispose()42 public void Dispose() 43 { 44 if(encryptor != null) 45 { 46 encryptor.Dispose(); 47 } 48 if(decryptor != null) 49 { 50 decryptor.Dispose(); 51 } 52 aesEngine.Dispose(); 53 } 54 EncryptBlockInSitu(Block b)55 public void EncryptBlockInSitu(Block b) 56 { 57 EncryptBlock(b, b); 58 } 59 EncryptBlock(Block b, Block result)60 public void EncryptBlock(Block b, Block result) 61 { 62 if(encryptor == null) 63 { 64 encryptor = aesEngine.CreateEncryptor(key, iv); 65 } 66 67 encryptor.TransformBlock(b.Buffer, 0, b.Buffer.Length, result.Buffer, 0); 68 lastBlock.CopyFrom(result); 69 } 70 DecryptBlockInSitu(Block b)71 public void DecryptBlockInSitu(Block b) 72 { 73 DecryptBlock(b, b); 74 } 75 DecryptBlock(Block b, Block result)76 public void DecryptBlock(Block b, Block result) 77 { 78 if(decryptor == null) 79 { 80 decryptor = aesEngine.CreateDecryptor(key, iv); 81 } 82 83 decryptor.TransformBlock(b.Buffer, 0, b.Buffer.Length, result.Buffer, 0); 84 lastBlock.CopyFrom(result); 85 } 86 87 public Block LastBlock { get { return lastBlock; } } 88 89 private ICryptoTransform encryptor; 90 private ICryptoTransform decryptor; 91 92 private readonly Block lastBlock; 93 private readonly Aes aesEngine; 94 private readonly byte[] key; 95 private readonly byte[] iv; 96 97 private const int AesBlockSizeInBytes = 16; 98 } 99 100 public class Block 101 { WithCopiedBytes(byte[] bytes)102 public static Block WithCopiedBytes(byte[] bytes) 103 { 104 var result = new Block(bytes.Length); 105 result.UpdateBytes(bytes); 106 return result; 107 } 108 UsingBytes(byte[] bytes)109 public static Block UsingBytes(byte[] bytes) 110 { 111 return new Block(bytes); 112 } 113 OfSize(int size)114 public static Block OfSize(int size) 115 { 116 return new Block(size); 117 } 118 UpdateByte(byte b)119 public void UpdateByte(byte b) 120 { 121 buffer[Index++] = b; 122 } 123 XorWith(Block b)124 public Block XorWith(Block b) 125 { 126 for(int i = 0; i < Math.Min(buffer.Length, b.buffer.Length); i++) 127 { 128 buffer[i] = (byte)(buffer[i] ^ b.buffer[i]); 129 } 130 131 return this; 132 } 133 UpdateBytes(byte[] bytes, int offset = 0, int length = -1)134 public void UpdateBytes(byte[] bytes, int offset = 0, int length = -1) 135 { 136 if(length == -1) 137 { 138 length = bytes.Length - offset; 139 } 140 141 Array.Copy(bytes, offset, buffer, Index, length); 142 Index += length; 143 } 144 PadSpaceLeft(byte value)145 public void PadSpaceLeft(byte value) 146 { 147 for(int i = Index; i < buffer.Length; i++) 148 { 149 buffer[i] = value; 150 } 151 Index = buffer.Length; 152 } 153 CopyTo(byte[] buffer)154 public void CopyTo(byte[] buffer) 155 { 156 this.buffer.CopyTo(buffer, 0); 157 } 158 CopyFrom(Block b)159 public void CopyFrom(Block b) 160 { 161 b.buffer.CopyTo(buffer, 0); 162 Index = b.Index; 163 } 164 165 public int SpaceLeft { get { return buffer.Length - Index; } } 166 public byte[] Buffer { get { return buffer; } } 167 public int Index { get; set; } 168 Block(byte[] buffer)169 private Block(byte[] buffer) 170 { 171 this.buffer = buffer; 172 } 173 Block(int size)174 private Block(int size) 175 { 176 buffer = new byte[size]; 177 } 178 179 protected readonly byte[] buffer; 180 } 181 } 182