Search code examples
pythonmodular-arithmeticcryptanalysis

My cryptanalyis of an affine cipher isn't working 100% of the time


I have to create a function that takes input as letters from a frequency analysis of the English language, "p1" and "p2", as well as a frequency analysis of the cipher-text, "C1" and "C2", as well as the alphabet length I am using "AL". I have created a function in Python to do this but it only works some of the time. Other times it gives me an error and I don't know why. The 2 equations are: s(r+p1)=C1(mod AL) s(r+p2)=C2(mod AL)

The code is supposed to calculate the multiplicative and additive keys for decrypting the given cipher-text.

Here is my code - the first function calculates the multiplicative modular inverse and the second function implements the equations.

def ModInverse(a, m):
    if gcd(a, m) != 1:
        return 'These are not co-prime.'

    # Calculate using the Extended Euclidean Algorithm:
    u1, u2, u3 = 1, 0, a
    v1, v2, v3 = 0, 1, m
    while v3 != 0:
        q = u3 // v3
        v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
    return u1 % m
def decryption_keys_affine(p1, p2, C1, C2, AL):

    s = p2 - p1

    p3 = s * p1

    p4 = (p3 % AL)

    p5 = C1 - p4

    p6 = AL + p5

    p7 = ModInverse(s, AL)

    p8 = p7 * p6

    r = p8 % AL

    multi = ModInverse(s, AL)
    add = AL - r

    print(multi, add)

When I give it this input:

>>> decryption_keys_affine(5, 20, 9, 26, 26)
7 20
>>> 

It displays the proper answers.

When I give it this input:

>>> decryption_keys_affine(5, 20, 41, 18, 42)
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    decryption_keys_affine(5, 20, 41, 18, 42)
  File "C:\Users\Herman\Desktop\crypto_math_functions.py", line 108, in decryption_keys_affine
    r = p8 % AL
TypeError: not all arguments converted during string formatting

It gives me that error and I don't know why. (The alphabet length for the first is 26 and for the second includes 10 digits and 6 symbols making it 42).


Solution

  • The reason is this line:

    return 'These are not co-prime.'
    

    The % operator performs the modulo operation when applied to integers.

    When applied to strings, it instead performs string formatting. In the case where the arguments provided to ModInverse are not coprime, it returns a string, which r = p8 % AL tries to format. Since the return string contains no format specifiers, it raises an exception.

    Rather than returning a string in such a situation, you should raise your own exception, for example:

    def ModInverse(a, m):
        if gcd(a, m) != 1:
            raise ValueError('The input arguments, {} and {}, are not coprime.'.format(a, m))
    
        # Calculate using the Extended Euclidean Algorithm:
        u1, u2, u3 = 1, 0, a
        v1, v2, v3 = 0, 1, m
        while v3 != 0:
            q = u3 // v3
            v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
        return u1 % m