vb.netcryptographyrsachinese-remainder-theorem

RunTime Error System.Security.Cryptography.CryptographicException: 'Bad Data. ' in vb.net when trying to import RSA parameters


Here's the code I am not sure if there's any hidden error but on runtime when trying to import the rsa parameters it pops up that error

Function ModInverse(ByVal a As BigInteger, ByVal b As BigInteger) As BigInteger

    Dim b0 As BigInteger = b
    Dim t As BigInteger
    Dim q As BigInteger
    Dim x0 As BigInteger = 0
    Dim x1 As BigInteger = 1

    If b = 1 Then Return 1

    While a > 1
        q = BigInteger.Divide(a, b)
        t = b
        b = BigInteger.Remainder(a, b)
        a = t
        t = x0
        x0 = BigInteger.Subtract(x1, BigInteger.Multiply(q, x0))
        x1 = t
    End While

    If x1 < 0 Then x1 += b0
    Return x1

End Function
Private Sub GenerateBTN_Click(sender As Object, e As EventArgs) Handles GenerateBTN.Click

End Sub

Private Sub TestBTN_Click(sender As Object, e As EventArgs) Handles TestBTN.Click
    Dim MyRSACryptoServiceProvider As New RSACryptoServiceProvider(384)
    Dim MyRSAParams As RSAParameters
    Dim P As BigInteger
    Dim Q As BigInteger
    Dim Modulus As BigInteger
    Dim Modulus1 As BigInteger
    Dim Exponent As BigInteger
    Dim D As BigInteger
    Dim DP As BigInteger
    Dim DQ As BigInteger
    Dim InverseQ As BigInteger
    Dim PrimeList, PrimeList2 As New List(Of BigInteger)
    Dim x As Integer = 1
    Dim RandomNumber1, RandomNumber2 As Integer
    Dim Random As New Random
    Using StreamReader As New StreamReader("G:\PrimeList384P1.txt")
        Dim line As String
        While x <= 1000
            line = StreamReader.ReadLine
            If x >= 501 And x <= 1000 Then
                PrimeList2.Add(BigInteger.Parse(line))
            Else
                PrimeList.Add(BigInteger.Parse(line))
            End If
            x += 1
        End While
    End Using
    MessageBox.Show("PrimeList1 Count" & PrimeList.Count & vbNewLine & "PrimeList2 Count" & PrimeList2.Count)
    RandomNumber1 = Random.Next(0, (PrimeList.Count - 1))
    RandomNumber2 = RandomNumber1
    Q = PrimeList(RandomNumber1)
    P = PrimeList2(RandomNumber2)
    Modulus = (P - 1) * (Q - 1)
    Modulus1 = Modulus + 1
    D = BigInteger.Divide(Modulus1, 65537)
    x = 0
    If BigInteger.GreatestCommonDivisor(P, Q) = 1 And BigInteger.GreatestCommonDivisor(Modulus, 65537) = 1 And BigInteger.GreatestCommonDivisor(D, Modulus) = 1 Then
    Else
        While x < 500
            Q = PrimeList(x)
            P = PrimeList2(x)
            Modulus = (P - 1) * (Q - 1)
            Modulus1 = Modulus + 1
            If BigInteger.Remainder(Modulus1, 65537) = 0 Then
                D = BigInteger.Divide(Modulus1, 65537)
            End If
            If BigInteger.GreatestCommonDivisor(P, Q) = 1 And BigInteger.GreatestCommonDivisor(Modulus, 65537) = 1 And BigInteger.GreatestCommonDivisor(D, Modulus) = 1 Then
                Exit While
            End If
            x += 1
        End While
    End If
    Exponent = 65537
    ExponentTextBox.Text = Exponent.ToString
    DTextBox.Text = D.ToString
    PTextBox.Text = P.ToString
    QTextBox.Text = Q.ToString
    ModulusTextBox.Text = Modulus.ToString
    DP = BigInteger.Remainder(D, (P - 1))
    DQ = BigInteger.Remainder(D, (Q - 1))
    DPTextBox.Text = DP.ToString
    DQTextBox.Text = DQ.ToString
    MyRSAParams.P = P.ToByteArray
    MyRSAParams.Q = Q.ToByteArray
    MyRSAParams.Modulus = Modulus.ToByteArray
    MyRSAParams.Exponent = Exponent.ToByteArray
    MyRSAParams.D = D.ToByteArray
    MyRSAParams.DP = DP.ToByteArray
    MyRSAParams.DQ = DQ.ToByteArray
    InverseQ = ModInverse(Q, P)
    MyRSAParams.InverseQ = InverseQ.ToByteArray
    InverseQTextBox.Text = InverseQ.ToString
    MyRSACryptoServiceProvider.ImportParameters(MyRSAParams)
End Sub

Function RandomNumberGenerator(ByVal List As List(Of BigInteger)) As Integer
    Dim Random As New Random
    Dim RandomInteger As Integer
    RandomInteger = Random.Next(0, List.Count)
    Return RandomInteger
End Function

Here's some passed(maybe) RSA Cryptography (CRT) data:

P=153914086704665934422965000391185991426092731525255651046673021110334850669910978950836977558144201721900890764527

Q=153914086704665934422965000391185991426092731525255651046673021110334850669910978950836977558144201721900890636321

Modulus=23689546086131422960647270026588478931532074235789438036179382904450240366918592625898413220651954314430049636574759400990197139024354395962962505626040856607248107788273729363773001668779017561229086034747388110074639423184320

Exponent=65537

D=361468271146549627853689824474548406724935139475249676307725146168580196940943171428329237234721673473458498810973334162231977951757852754367189612372260808508905012256797371923844571292232136979554847410583153181784937107

DP=114907738137020230395758602608296812312065934785963783731504609257159521698848045807811642857696865920764862342291

DQ=108172220785463370912946395441018459268593789982044879796294602321467617099594117681241911993654301101831866315347

InverseQ=70202908196408513230673481177755980380197687014666822974402900452935518326945574435736969694613344805169792281463

I was using reference from these websites

https://www.di-mgt.com.au/crt_rsa.html#PKCS1

https://www.c-sharpcorner.com/forums/modular-inverse-code

Here's the Error List:

System.Security.Cryptography.CryptographicException
  HResult=0x80090005
  Message=Bad Data.
  Source=mscorlib
  StackTrace:
   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey)
   at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters)
   at RSATesting.Form1.TestBTN_Click(Object sender, EventArgs e) in C:\Users\chew\source\repos\RSATesting\Form1.vb:line 106
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
   at RSATesting.My.MyApplication.Main(String[] Args) in :line 81

Here's the other attempt where i try to do it with some changes on the main function.

Private Sub TestBTN_Click(sender As Object, e As EventArgs) Handles TestBTN.Click
    Dim MyRSACryptoServiceProvider As New RSACryptoServiceProvider(384)
    Dim MyRSAParams As RSAParameters
    Dim P As BigInteger
    Dim Q As BigInteger
    Dim Modulus As BigInteger
    Dim Modulus1 As BigInteger
    Dim Exponent As BigInteger
    Dim D As BigInteger
    Dim DP As BigInteger
    Dim DQ As BigInteger
    Dim InverseQ As BigInteger
    Dim PrimeList, PrimeList2 As New List(Of BigInteger)
    Dim x As Integer = 1
    Dim RandomNumber1, RandomNumber2 As Integer
    Dim Random As New Random
    Using StreamReader As New StreamReader("G:\PrimeList384P1.txt")
        Dim line As String
        While x <= 1000
            line = StreamReader.ReadLine
            If x >= 501 And x <= 1000 Then
                PrimeList2.Add(BigInteger.Parse(line))
            Else
                PrimeList.Add(BigInteger.Parse(line))
            End If
            x += 1
        End While
    End Using
    RandomNumber1 = Random.Next(0, (PrimeList.Count - 1))
    RandomNumber2 = RandomNumber1
    Q = PrimeList(RandomNumber1)
    P = PrimeList2(RandomNumber2)
    Modulus = (P - 1) * (Q - 1)
    D = ModInverse(65537, Modulus)
    x = 0
    If BigInteger.GreatestCommonDivisor(P, Q) = 1 And BigInteger.GreatestCommonDivisor(Modulus, 65537) = 1 And BigInteger.GreatestCommonDivisor(D, Modulus) = 1 Then
    Else
        While x < 500
            Q = PrimeList(x)
            P = PrimeList2(x)
            Modulus = (P - 1) * (Q - 1)
            D = ModInverse(65537, Modulus)
            If BigInteger.GreatestCommonDivisor(P, Q) = 1 And BigInteger.GreatestCommonDivisor(Modulus, 65537) = 1 And BigInteger.GreatestCommonDivisor(D, Modulus) = 1 Then
                Exit While
            End If
            x += 1
        End While
    End If
    Exponent = 65537
    ExponentTextBox.Text = Exponent.ToString
    DTextBox.Text = D.ToString
    PTextBox.Text = P.ToString
    QTextBox.Text = Q.ToString
    ModulusTextBox.Text = Modulus.ToString
    DP = BigInteger.Remainder(D, (P - 1))
    DQ = BigInteger.Remainder(D, (Q - 1))
    InverseQ = ModInverse(Q, P)
    DPTextBox.Text = DP.ToString
    DQTextBox.Text = DQ.ToString
    InverseQTextBox.Text = InverseQ.ToString
    MyRSAParams.P = ExportUnsignedBigEndian(P)
    MyRSAParams.Q = ExportUnsignedBigEndian(Q)
    MyRSAParams.Modulus = ExportUnsignedBigEndian(Modulus)
    MyRSAParams.Exponent = ExportUnsignedBigEndian(Exponent)
    MyRSAParams.D = ExportUnsignedBigEndian(D)
    MyRSAParams.DP = ExportUnsignedBigEndian(DP)
    MyRSAParams.DQ = ExportUnsignedBigEndian(DQ)
    MyRSAParams.InverseQ = ExportUnsignedBigEndian(InverseQ)
    MyRSACryptoServiceProvider.ImportParameters(MyRSAParams)
End Sub

System.Security.Cryptography.CryptographicException HResult=0x80090005

Message=Bad Data.

Source=mscorlib StackTrace:

at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)

at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey)

at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters)

at RSATesting.Form1.TestBTN_Click(Object sender, EventArgs e) in C:\Users\chew\source\repos\RSATesting\Form1.vb:line 109

at System.Windows.Forms.Control.OnClick(EventArgs e) at System.Windows.Forms.Button.OnClick(EventArgs e)

at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)

at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ButtonBase.WndProc(Message& m)

at System.Windows.Forms.Button.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)

at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at

System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32

pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason,

ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason,

ApplicationContext context) at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun() at

Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel() at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)

at RSATesting.My.MyApplication.Main(String[] Args) in :line 81


Solution

  • MyRSAParams.P = P.ToByteArray
    

    BigInteger's ToByteArray produces a signed, little-endian value. The number 65532 (0xFFFC) produces the byte array new byte[] { 0xFC, 0xFF, 0x00 }.

    RSAParameters values are unsigned, big-endian values. So that same byte array (which we intended to be 0xFFFC) is interpreted as 0xFCFF00 (16,580,352).

    To turn signed little-endian into unsigned big-endian you need to remove the last byte (if it's zero), then reverse things.

    I can't write VB reliably, so here's some C#:

    private static byte[] ExportUnsignedBigEndian(BigInteger val)
    {
        byte[] export = val.ToByteArray();
    
        if (export[export.Length - 1] == 0)
        {
            Array.Resize(ref export, export.Length - 1);
        }
    
        Array.Reverse(export);
        return export;
    }
    

    Or, if you're building for netcoreapp2.1 or higher, or netstandard2.1 or higher:

    val.ToByteArray(isUnsigned: true, isBigEndian: true);