1 //
2 // Copyright (c) 2010-2022 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.Utilities;
8 using System;
9 using System.Linq;
10 using System.Numerics;
11 
12 namespace Antmicro.Renode.Peripherals.Miscellaneous.Crypto
13 {
14     public class RSAServiceProvider
15     {
RSAServiceProvider(InternalMemoryManager manager)16         public RSAServiceProvider(InternalMemoryManager manager)
17         {
18             this.manager = manager;
19         }
20 
ModularExponentation()21         public void ModularExponentation()
22         {
23             manager.TryReadDoubleWord((long)RSARegisters.ExponentationModulusLength, out var modulusLength);
24             manager.TryReadDoubleWord((long)RSARegisters.ExponentLength, out var exponentLength);
25             var baseAddress = (long)RSARegisters.BaseAddress + exponentLength * 4;
26 
27             var n = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.Modulus, modulusLength);
28             var e = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.Exponent, exponentLength);
29             var operand = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, baseAddress, modulusLength);
30 
31             var resultBytes = BigInteger.ModPow(operand, e, n).ToByteArray();
32             AthenaX5200_BigIntegerHelper.StoreBigIntegerBytes(manager, modulusLength, resultBytes, baseAddress);
33         }
34 
ModularReduction()35         public void ModularReduction()
36         {
37             manager.TryReadDoubleWord((long)RSARegisters.ReductionModulusLength, out var modulusLength);
38             manager.TryReadDoubleWord((long)RSARegisters.ReductionOperandLength, out var operandLength);
39 
40             var n = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.Modulus, modulusLength);
41             var a = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.Operand, operandLength);
42 
43             var resultBytes = (a % n).ToByteArray();
44             AthenaX5200_BigIntegerHelper.StoreBigIntegerBytes(manager, modulusLength, resultBytes, (long)RSARegisters.Operand);
45         }
46 
DecryptData()47         public void DecryptData()
48         {
49             manager.TryReadDoubleWord((long)RSARegisters.DecryptionModulusLength, out var modulusLength);
50 
51             var n = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.N, modulusLength * 2);
52 
53             // Step 1:
54             // m1 = c^dp mod p
55             var c = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.Cipher, modulusLength * 2);
56             var dp = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.DP, modulusLength);
57             var p = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.P, modulusLength);
58             var m1 = BigInteger.ModPow(c, dp, p);
59 
60             // Step 2:
61             // m2 = c^dq mod q
62             var dq = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.DQ, modulusLength);
63             var q = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.Q, modulusLength);
64             var m2 = BigInteger.ModPow(c, dq, q);
65 
66             // Step 3:
67             // h = (qInv * (m1 - m2)) mod p
68             var qInv = AthenaX5200_BigIntegerHelper.CreateBigIntegerFromMemory(manager, (long)RSARegisters.QInverted, modulusLength);
69             var x = m1 - m2;
70             // We add in an extra p here to keep x positive
71             // example: https://www.di-mgt.com.au/crt_rsa.html
72             while(x < 0)
73             {
74                 x += p;
75             }
76             var h = (qInv * x) % p;
77 
78             // Step 4:
79             // m = m2 + h * q
80             var mBytes = (m2 + h * q).ToByteArray();
81             AthenaX5200_BigIntegerHelper.StoreBigIntegerBytes(manager, (uint)mBytes.Length, mBytes, (long)RSARegisters.BaseAddress);
82         }
83 
Reset()84         public void Reset()
85         {
86             manager.ResetMemories();
87         }
88 
89         private readonly InternalMemoryManager manager;
90 
91         private enum RSARegisters
92         {
93             ReductionOperandLength = 0x8,
94             ReductionModulusLength = 0xC,
95             ExponentationModulusLength = 0x10,
96             Operand = 0x10,
97             ExponentLength = 0x14,
98             Exponent = 0x18,
99             BaseAddress = 0x18,
100             DecryptionModulusLength = 0x30,
101             Cipher = 0x1e4,
102             DP = 0x4f0,
103             DQ = 0x5b0,
104             QInverted = 0x670,
105             Modulus = 0x1000,
106             P = 0x1348,
107             Q = 0x14cc,
108             N = 0x1650,
109         }
110     }
111 }
112