1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Logging;
8 using Antmicro.Renode.Peripherals.Bus;
9 using System;
10 using System.Linq;
11 using System.Numerics;
12 using System.Security.Cryptography;
13 
14 namespace Antmicro.Renode.Peripherals.Miscellaneous.Crypto
15 {
16     public class DSAServiceProvider
17     {
DSAServiceProvider(InternalMemoryManager manager, IBusController bus)18         public DSAServiceProvider(InternalMemoryManager manager, IBusController bus)
19         {
20             this.manager = manager;
21             this.bus = bus;
22         }
23 
SignDMA()24         public void SignDMA()
25         {
26             // The driver is encoding data length as one doubleword: ((uiN<<16) | uiL))
27             manager.TryReadDoubleWord((long)DSARegisters.DataLengthEncoded, out var dataLengthEncoded);
28             var uiL = dataLengthEncoded & 0xFFFF;
29             var uiN = dataLengthEncoded >> 16;
30 
31             var g = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)DSARegisters.G, uiL);
32             var k = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)DSARegisters.K, uiN);
33             var p = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)DSARegisters.P, uiL);
34             var q = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)DSARegisters.Q, uiN);
35             var x = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)DSARegisters.X, uiN);
36 
37             // Step 1:
38             // r = (g^k mod p) mod q
39             var r = BigInteger.ModPow(g, k, p) % q;
40             var rBytes = r.ToByteArray();
41             AthenaX5200_BigIntegerHelper.StoreBigIntegerBytes(manager, (uint)rBytes.Length, rBytes, (long)DSARegisters.R);
42 
43             manager.TryReadDoubleWord((long)DSARegisters.MessageLenth, out var msgLength);
44             manager.TryReadDoubleWord((long)DSARegisters.MessageExternalAddress, out var msgExternalAddress);
45             var msgBytes = bus.ReadBytes(msgExternalAddress, (int)msgLength);
46             // We could use SHA384.HashData static method, but it's not available in Mono.
47             var hash = SHA384.Create().ComputeHash(msgBytes);
48 
49             var z = AthenaX5200_BigIntegerHelper.CreateBigInteger(hash, Math.Min(q.ToByteArray().Length, hash.Length));
50 
51             // Step 2:
52             // s = (k^-1(z + xr)) mod q
53             var inverseK = AthenaX5200_BigIntegerHelper.CalculateModularInverse(k, q);
54 
55             var S = (inverseK * (z + (x * r))) % q;
56             var sBytes = S.ToByteArray();
57             AthenaX5200_BigIntegerHelper.StoreBigIntegerBytes(manager, (uint)sBytes.Length, sBytes, (long)DSARegisters.S);
58         }
59 
60         private readonly IBusController bus;
61         private readonly InternalMemoryManager manager;
62 
63         private enum DSARegisters
64         {
65             R = 0x20,
66             S = 0x40,
67             MessageLenth = 0x44,
68             MessageExternalAddress = 0x48,
69             G = 0x1348,
70             K = 0x14CC,
71             X = 0x14F0,
72             Q = 0x1000,
73             P = 0x1044,
74             DataLengthEncoded = 0x2410
75         }
76     }
77 }
78