Sunday, 30 July 2017

Cryptography - VBA code for Wikipedia's RSA example

So, following on from studying some cryptography I can give some VBA code which implements RSA or at least the example given on the RSA Wikipedia article. So the two primes p and q are given; calculating n is easy (multiply); we can use worksheet function lcm for the totient;e is given;I hunted around for some logic for "module multiplicative inverse" and finally we have the components for the private and public keys.

Also shown is some code to encrypt a message (very short one character "A" represented by ASCII 65) and decrypt it back to the original. To encrypt a larger message needs an arithmetic vehicle larger that that available in VBA, you'll see I'm declaring variables as Currency to get as many bits as possible but even this has limits when raising a number to a very high power exponentional.

Anyway, simple version that allows VBA programmer to step through the wikipedia example is given here ...

Option Explicit
Option Private Module

Private Type udtPublicKey
    n As Currency
    e As Currency
End Type

Private Type udtPrivateKey
    n As Currency
    d As Currency
End Type

'***************************************************
'               .__
'  _____ _____  |__| ____
' /     \\__  \ |  |/    \
'|  Y Y  \/ __ \|  |   |  \
'|__|_|  (____  /__|___|  /
'      \/     \/        \/
'***************************************************

Private Sub Main()

    Dim p As Currency
    Dim q As Currency
    Dim n As Currency
    Dim lambda_n As Currency
    Dim e As Currency
    Dim d As Currency


    p = 61
    q = 53
    n = p * q
    lambda_n = Application.Lcm(p - 1, q - 1)
    e = 17
    Debug.Assert IsCoPrime(e, lambda_n)
    
    d = ModularMultiplicativeInverse(e, lambda_n)
    Debug.Assert e <> d

    Dim uPrivate As udtPrivateKey
    uPrivate.d = d
    uPrivate.n = n
    
    Dim uPublic As udtPublicKey
    uPublic.e = e
    uPublic.n = n
        
    '* m is the message to encrypt, it needs to be a number
    '* 65 is ASCII for "A"
    Dim m As Currency
    m = 65
    
    '* c is the encrypted message
    Dim c As Currency
    c = Encrypt(m, uPublic)
    
    '* m2 is the decrypted message
    Dim m2 As Currency
    m2 = Decrypt(c, uPrivate)
    
    '* and the decrypted message should match the original
    Debug.Assert m2 = m
     
End Sub


Private Function Encrypt(ByVal m As Currency, _
                    ByRef uPublic As udtPublicKey) As Currency
    If m > uPublic.n Then Err.Raise vbObjectError, , _
            "#text is bigger than modulus, no way to decipher!"
    
    Dim lLoop As Long
    Dim lResult As Currency
    lResult = 1
    For lLoop = 1 To uPublic.e
    
        lResult = ((lResult Mod uPublic.n) * (m Mod uPublic.n)) Mod uPublic.n
    Next lLoop
    Encrypt = lResult
End Function

Private Function Decrypt(ByVal c As Currency, _
                    ByRef uPrivate As udtPrivateKey) As Currency
    If c > uPrivate.n Then Err.Raise vbObjectError, , _
            "#text is bigger than modulus, no way to decipher!"
    Dim lLoop As Long
    Dim lResult As Currency
    lResult = 1
    For lLoop = 1 To uPrivate.d
        lResult = ((lResult Mod uPrivate.n) * (c Mod uPrivate.n)) Mod uPrivate.n
    Next lLoop

    
    Decrypt = lResult
End Function

Private Function IsCoPrime(ByVal a As Currency, ByVal b As Currency) As Boolean
    IsCoPrime = (Application.Gcd(a, b) = 1)
End Function

Private Function ModularMultiplicativeInverse(ByVal e As Currency, _
                    ByVal lambda_n As Currency)
    Dim lLoop As Currency
    For lLoop = 1 To lambda_n
        If lLoop <> e Then
            Dim lComp As Currency
            lComp = lLoop * e Mod lambda_n
            If lComp = 1 Then
                ModularMultiplicativeInverse = lLoop
                Exit Function
            End If
        End If
    Next
SingleExit:
End Function




No comments:

Post a Comment