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 NUnit.Framework;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Debugging;
11 using Antmicro.Renode.Peripherals.Miscellaneous;
12 using System.Collections.Generic;
13 
14 namespace Antmicro.Renode.PeripheralsTests
15 {
16     [TestFixture]
17     public class OpenTitan_AES_Tests
18     {
19         [SetUp]
SetUp()20         public void SetUp()
21         {
22             peripheral = new OpenTitan_AES(new Machine());
23         }
24 
25         [Test]
ShouldStartInIdleMode()26         public void ShouldStartInIdleMode()
27         {
28             var status = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.Status);
29             Assert.AreEqual(0x1, status & 0x1);
30         }
31 
32         [Test]
ShouldChangeStatusWhenSetToAutomaticMode()33         public void ShouldChangeStatusWhenSetToAutomaticMode()
34         {
35             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Control, 0x8);
36             var status = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.Status);
37             Assert.AreEqual(0x10, status & 0x10);
38         }
39 
40         [Test]
ShouldKeepTrackOfDataWrites()41         public void ShouldKeepTrackOfDataWrites()
42         {
43             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.InputData_0, 0x1234);
44 
45             Assert.IsFalse(peripheral.InputDataReady);
46             WriteInputData(encrypted);
47             Assert.IsTrue(peripheral.InputDataReady);
48         }
49 
50         [Test]
51         //This test is based on OpenTitan AES smoketest binary
ShouldGiveCorrectEncryptionOutput()52         public void ShouldGiveCorrectEncryptionOutput()
53         {
54             SetKeyShare();
55 
56             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Control, 0x205);
57             WriteInputData(decrypted);
58 
59             for(int i = 0; i < 4; i++)
60             {
61                 var actual = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0 + 4 * i);
62                 Assert.AreEqual(encrypted[i], actual, "DATA_OUT_{0}: Expected: 0x{1:X}, Got: 0x{2:x}", i, encrypted[i], actual);
63             }
64         }
65 
66         [Test]
67         //This test is based on OpenTitan AES smoketest binary
ShouldWorkInManualModeToo()68         public void ShouldWorkInManualModeToo()
69         {
70             SetKeyShare();
71 
72             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Control, 0x8405);
73             WriteInputData(decrypted);
74 
75             // Before trigger
76             for(int i = 0; i < 4; i++)
77             {
78                 var actual = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0 + 4 * i);
79                 Assert.AreEqual(0x0, actual, "DATA_OUT_{0}: Expected to be zero before trigger, Got: 0x{1:x}", i, actual);
80             }
81 
82             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Trigger, 0x1);
83 
84             // After trigger
85             for(int i = 0; i < 4; i++)
86             {
87                 var actual = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0 + 4 * i);
88                 Assert.AreEqual(encrypted[i], actual, "DATA_OUT_{0}: Expected: 0x{1:X}, Got: 0x{2:x}", i, encrypted[i], actual);
89             }
90 
91         }
92 
93         [Test]
94         //This test is based on OpenTitan AES smoketest binary
ShouldGiveCorrectDecryptionOutput()95         public void ShouldGiveCorrectDecryptionOutput()
96         {
97             SetKeyShare();
98 
99             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Control, 0x206);
100 
101             WriteInputData(encrypted);
102 
103             for(int i = 0; i < 4; i++)
104             {
105                 var actual = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0+ 4 * i);
106                 Assert.AreEqual(decrypted[i], actual, "DATA_OUT_{0}: Expected: 0x{1:X}, Got: 0x{2:x}", i, decrypted[i], actual);
107             }
108         }
109 
110         [Test]
ShouldRandomizeDataOutputOnTrigger()111         public void ShouldRandomizeDataOutputOnTrigger()
112         {
113             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Trigger, 0x4);
114             uint sum = 0;
115             for(int i = 0; i < 4; i++)
116             {
117                 sum += peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0 + 4 * i);
118             }
119             Assert.AreNotEqual(0x0, sum);
120         }
121 
122         [Test]
ShouldRandomizeInputRegistersOnTrigger()123         public void ShouldRandomizeInputRegistersOnTrigger()
124         {
125             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Control, 0x1005);
126 
127             // We only test if the output is different after randomizing
128             WriteInputData(decrypted);
129             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Trigger, 0x6);
130             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Trigger, 0x1);
131 
132             for( var i = 0; i < 4; i++)
133             {
134                 var actual = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0 + 4 * i);
135                 Assert.AreNotEqual(encrypted[i], actual);
136             }
137         }
138 
139         [Test]
ShouldBeAbleToDoMultipleTransformationsWithASingleKey()140         public void ShouldBeAbleToDoMultipleTransformationsWithASingleKey()
141         {
142             SetKeyShare();
143 
144             peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.Control, 0x206);
145 
146             WriteInputData(decrypted);
147             WriteInputData(encrypted);
148 
149             for(int i = 0; i < 4; i++)
150             {
151                 var actual = peripheral.ReadDoubleWord((long)OpenTitan_AES.Registers.OutputData_0 + 4 * i);
152                 Assert.AreEqual(decrypted[i], actual, "DATA_OUT_{0}: Expected: 0x{1:X}, Got: 0x{2:x}", i, decrypted[i], actual);
153             }
154         }
155 
WriteInputData(uint[] data)156         private void WriteInputData(uint[] data)
157         {
158             DebugHelper.Assert(data.Length == 4);
159 
160             for(var i = 0; i < 4; i++)
161             {
162                 peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.InputData_0 + 4 * i, data[i]);
163             }
164         }
165 
SetKeyShare()166         private void SetKeyShare()
167         {
168             for(int i = 0; i < 8; i++)
169             {
170                 peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.InitialKeyShare0_0 + i * 4, keyShare0[i]);
171                 peripheral.WriteDoubleWord((long)OpenTitan_AES.Registers.InitialKeyShare1_0 + i * 4, keyShare1[i]);
172             }
173         }
174 
175         private OpenTitan_AES peripheral;
176 
177         private readonly uint[] keyShare0 = { 0x3C2D1E0F, 0x78695A4B, 0xB4A59687, 0xF0E1D2C3, 0x29380B1A, 0x6D7C4F5E, 0xA1B08392, 0xE5F4C7D6 };
178         private readonly uint[] keyShare1 = { 0x3F2F1F0F, 0x7F6F5F4F, 0xBFAF9F8F, 0xFFEFDFCF, 0x3A2A1A0A, 0x7A6A5A4A, 0xBAAA9A8A, 0xFAEADACA };
179         private readonly uint[] encrypted = { 0xCAB7A28E, 0xBF456751, 0x9049FCEA, 0x8960494B };
180         private readonly uint[] decrypted = { 0x33221100, 0x77665544, 0xBBAA9988, 0xFFEEDDCC };
181     }
182 }
183