Take the 2-minute tour ×
Cryptography Stack Exchange is a question and answer site for software developers, mathematicians and others interested in cryptography. It's 100% free, no registration required.

I decided to program a relatively trivial encryption algorithm in my downtime. This algorithm takes a seed from a user (supports floating point seeds), and then adds 1 to the seed for every iteration of each character of a message, performing a bitwise xor with a pseudorandomly generated value. As Python uses Mersenne twister, a non-cryptographic pseudorandom generator, I figured that this encryption algorithm must have some vulnerabilities, as Mersenne twister is not cryptographically secure.

To name a few:

  1. Can an encrypted message be plaintext attacked like a regular low byte key XOR encryption?

  2. Can an attacker guess the value of the seed based upon patterns in the encrypted message?

  3. Can multiple inputted seeds end up with the same encrypted message?

    import random
    import codecs
    import binascii
    import math
    def encrypt(x):
        y = float(input("Enter the encryption key  -->"))
        random.seed(y)
        i = 0
        x = list(x)
        while i < len(x):
            y += 1
            rand = random.randint(1,random.randint(200,400))
            random.seed(rand)
            x[i] = chr(ord(x[i]) ^ rand ^ abs((~int(rand/2))))
            i += 1
        x = "".join(x)
        x = str(binascii.hexlify(x.encode("utf-8")))
        x = list(x)
        x.pop(x.index("'"));x.pop(x.index("b"));x.pop(x.index("'"))
        return "".join(x)
    def decrypt(x):
        x = bytes.fromhex(x).decode('utf-8')
        y = float(input("Enter the decryption key -->"))
        random.seed(y)
        i = 0
        x = list(x)
        while i < len(x):
            y += 1
            rand = random.randint(1,random.randint(200,400))
            random.seed(rand)
            x[i] = chr(ord(x[i]) ^ rand ^ abs((~int(rand/2))))
            i += 1
        x = "".join(x)
        return x
    def instructions():
        print("Welcome to the RBES3 (Randomized Bitwise Encryption Standard 3) symmetric key encryption program.")
        print("Choose to either decrypt or encrypt your string in this program. \n")
    def main():
        x = input("Would you like decrypt encrypt a string? (d for decrypt, e for encrypt) -->")
        if x == "d":
            args = input("Would you like to decrypt a string or a file? (s/f) -->").lower()
            if args == "f":
                filename = input("Enter the path to the file that you want to decrypt. -->")
                file = open(filename,"r+")
                dcrypt = open("_"+filename[-(len(filename)//3+1)::]+"_decrypted", "w") 
                try:
                    done = decrypt(file.readlines()[0])
                    print("The decrypted string is --> "+done)
                    dcrypt.write(done)
                    file.close()
                except:
                    print("\nOne or more of your parameters were invalid.  Please check your input and try again.  If you are using an ASCII encoding, check your key, as ASCII does not support special characters.")
            if args == "s":
                string = input("Enter a string to be decrypted here. -->")
                try:
                    print("The decrypted string is --> "+decrypt(string))
                except:
                    print("\nOne or more of your parameters were invalid.  Please check your input and try again.")
        if x == "e":
            args = input("Would you like to encrypt a string or a file? (s/f) -->").lower()
            if args == "f":
                filename = input("Enter the path to the file that you want to encrypt. -->")
                file = open(filename,"r+")
                ecrypt = open("_"+filename[-(len(filename)//3+1)::]+"_encrypted", "w") 
                try:
                    done = encrypt(file.readlines()[0])
                    print("The decrypted string is --> "+done)
                    ecrypt.write(done)
                    file.close()
                except:
                    print("\nOne or more of your parameters were invalid.  Please check your input and try again.")
          if args == "s":
                string = input("Enter a string to be encrypted here. -->")
                try:
                    print("The encrypted string is --> "+encrypt(string))
                except:
                    print("\nOne or more of your parameters were invalid.  Please check your input and try again.")
    main()
    

Examples:

    "This is a test message" (no quotes)
    seed = 29
    encrypted message: 670967c2ad34345ac6a053c295c2827cc3bbc7ac6ac68a1ec291c2b978c3afc7bd
share|improve this question

migrated from security.stackexchange.com Apr 1 at 9:01

This question came from our site for Information security professionals.

14  
Vulnerability #1 - you're rolling your own crypto. –  Iszi Apr 1 at 4:20
3  
@lszi I suspect the author already knows that. And that's a cause of vulnerabilities, but it's not actually a vulnerability. –  immibis Apr 1 at 7:53

1 Answer 1

up vote 14 down vote accepted

Vulnerability #1 You're rolling your own crypto. I'm stealing this from Iszi's comment, but it was my first thought when I saw this as well. The general consensus from cryptographers (read: universal accord with no dissent from anyone with more than a passing interest in cryptography) is that it is terribly difficult to roll your own cryptography until you have done sufficient study to understand the existing ones. There are just too many clever attacks out there. I recommend looking at Length Extension Attacks as an excellent example of the kind of clever thinking that crypto teams deal with.

(Edit: given that this has been migrated to Cryptography and the question has been raised, this is not technically a cryptographic vulnerability. However, it is such an extraordinarily important issue to pay attention to that my opinion is that it should be treated at least as seriously as a vulnerability that completely cracks the system. That sort of thinking ensures we never make the mistake of thinking something is secure simply because nobody has had a reason to spend the time it takes to crack it)

Vulnerability #2 Severely limited keyspace. You use random.seed(y), which hashes y and seeds the Mersene Twister using that value. Your float can have no more than 64 bits of entropy, because that's how big a float is. A 64-bit keyspace is very susceptible to brute force attacks.

Issue #2a random.seed(y) on a float relies on the built in python hash function. This function is implementation defined AND is different between 32-bit and 64-bit pythons. Encoding done on 32bit machines will be unreadable on 64-bit machines

Vulnerability #3 You're dependent on the user to provide good crypto keys for each message. Realistically, we're really bad at key distribution, and you're going to be weak because of that. Consider that one of the ways the Enigma was broken was that they chose to transmit the key twice, instead of once, and that gave the Allies enough extra information to crack their codes.

Vulnerability #4 Correlation in XOR bits. The bit-twiddle and abs are nice, but they don't provide much security directly. However, XORing by rand AND rand/2 yields a hole because there is now a correlation between the bits you are XORing the message with. A clever frequency attack based on correlation between bits would reveal key information, leading to.

Vulnerability #5,6,7,8,9... All remaining vulnerabilities are simple: you're using a non cryptographic RNG to do cryptography. That is instant doom for any crypto algorithm. Nobody will give your algorithm any thought if you're using a non-crypto RNG without some hardcore whitening steps. Mersene Twister leaks its entire state in 624 observed values. While the attacker wont have all of them, all they have to do is start collecting what data they do know, and attack the Twister with it. Twister was never designed to hold up to such an attack.

In general, I would not trust the algorithm unless I could replace Mersene Twister with a simple counter: 1, 2, 3, 4, 5... When designing crypto, you should assume Mersene Twisters provide no security at all, and design all of your security on top of it.


If this seems a little forward, it's because you really shouldn't be trying to learn crypto by making your own algorithm like this. Its just too easy to find an algorithm which can't be broken simply because nobody can be bothered to break it. Designing a real crypto algorithm is hard... really hard. PhDs who have spent their life developing crypto can spend thousands of hours carefully crafting an algorithm, and the community can spend tens of thousands of hours trying to verify it's integrity, just to have it crumble before their eyes due to an oversight.

If you are interested in entering the field of crypto, it's actually a field that is more forgiving to those who read books first, then try to design crypto. In fact, I can't remember which major cryptographer said it, but there was a quote that he won't even take the time to look at an algorithm unless the people behind it have broken six or seven algorithms themselves. Only after they've broken many algorithms will he trust them to write one that's hard to break.

share|improve this answer
8  
Bruce Schneier (1998): "Anyone, from the most clueless amateur to the best cryptographer, can create an algorithm that he himself can't break. It's not even hard. What is hard is creating an algorithm that no one else can break, even after years of analysis." –  Alasjo Apr 1 at 6:22
    
#3: It didn't give the allies enough to crack the code. It gave Polish mathematicians pre-war enough information to reverse engineer the exact internal structure of the Enigma machine. Which means the damage was done when Enigma was used in an unsafe way, and later changes to safer ways couldn't undo the damage. (They needed 80-90 messages sent with the same settings, PLUS the cable connections used, which a cleaner looking at the machine could have delivered). –  gnasher729 Apr 1 at 8:56
    
-1 "You're rolling your own crypto" Is not a vulnerability of the algorithm, it is a statement purely about the author and the context. I understand that you want to warn people against using this, but simply listing the actual vulnerabilities should be plenty. –  eBusiness Apr 1 at 9:22
1  
@eBusiness I added an edit paragraph after vulnerability #1 to address this. See if it meets your opinions. This forum was originally on Information Security, not cryptography, so I was allowing a little more use of the English word "vulnerability," rather than the strict crypto definition. I was originally comfortable with the wording from the perspective of "I must treat your algorithm as vulnerable, even if I haven't found one, simply because it is a home-rolled crypto." If it makes me act as though it is vulnerable, it makes some sense to treat it as a vulnerability. –  Cort Ammon Apr 1 at 14:25
    
@CortAmmon I don't think answering like that is good on Security either. It is information completely tangential to the answer, if you feel the need to say it, make sure to separate it clearly from the answer. You risk that the advice is ignored if you oversell it with untrue claims. –  eBusiness Apr 1 at 17:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.