Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Asking a favour
#1
Good day!

I would like to ask a massive favour from you guys. Could someone be kind and write a very small, simple Python program for me please? Those who are familiar with Python can probably write it in about five minutes.

Long story short, I have downloaded a really interesting and fun historical TSEC / KL-7 Adonis cipher machine simulator. It has a number of settings, called "key" that can be changed. The "key" was changed on a daily basis. Right now I have been using the random.org website to get new settings but it is very time consuming, I definitely wouldn't change my "key" every day since it takes 10-15 minutes to generate them, given the amount of options the machine has. However, a small program could generate random new keys at a press of a button and I could just copy/paste them straight into my "code book". Would someone please be kind and write a small program that could generate these random keys?

The settings, in a nutshell, without going into details, would be the following.

There are 8 encryption rotors. However, the 4th rotor has only two settings available so the NOTCH RING and NOTCH RING SET values are not calculated for the 4th rotor.

1st line -ROTOR CORE
Eight values are needed, each value can be letter A, B, C, D, E, F, G, H, I, J, K and L. Each value can occur only once, so no two rotor core can use the same letter. An option to include a thirteenth letter, which is letter M would be awesome but not essential.

2nd line -ALPHABET RING SET
Again, eight values are needed. Each value can be a number between 1-36, however, this time, a value can occur multiple times.

3rd line -NOTCH RING
Only seven values are needed here (the 4th rotor is fixed) and each value can be a number between 1-11 and each value can occur only once.

4th line -NOTCH RING SET
Seven values are needed (same as above), each value can be any of these: A, B, B+, C, D, E, E+, F, G, G+, H, I, J, J+, K, L, M, M+ N, O, O+, P, Q, R, R+, S, T, T+, U, V, W, W+, X, Y, Z, Z+. Each value can occur multiple times.

That is it. I would image a .py program which, after pressing RUN, gives a random result that looks something like this, nicely formatted so that each value is displayed under the relevant encryption rotor (couldn't format the below so it does not display it nicely but you get the idea):

1 2 3 4 5 6 7 8 <---Encryption rotor
-----------------------------
D B F L E A K G <--- 1st line, ROTOR CORE
11 8 34 32 35 3 20 15 <--- 2nd line, ALPHABET RING SET
7 10 3 11 1 5 2 <--- 3rd line, NOTCH RING
W+ H A S B+ U S <--- 4th line, NOTCH RING SET

Thank you kindly for your attention and I am looking forward to hearing from you.
Reply
#2
Please do not double post It's against forum rules
Reply
#3
I thought I can edit the first one so that it will be completely different but I couldn't edit anymore.

[Image: yRlKATM]
Reply
#4
A small training session in my favorite language
#!/usr/bin/env python3
import itertools as itt
import os

def iranduint():
    yield from itt.chain.from_iterable(os.urandom(1024) for k in itt.count())
iranduint = iranduint()

def irandrange(n):
    sz = n.bit_length()
    if sz > 8:
        raise ValueError('Expected value < 256, got', n)
    m = 2 ** sz
    assert((m/2) <= n < m)
    for x in iranduint:
        x %= m
        if x < n:
            yield x
            
def irandchoice(n):
    s = set()
    while True:
        x = next(irandrange(n))
        if x in s:
            continue
        s.add(x)
        yield x

def make_key():
    rotor = [x for x in range(1, 9)]
    alpha = [x for x in "ABCDEFGHIJKL"]
    chx = irandchoice(len(alpha))
    core = [alpha[next(chx)] for i in range(8)]
    g36 = irandrange(36)
    ring = [1 + next(g36) for i in range(8)]
    g11 = irandchoice(11)
    notchring = [1 + next(g11) for i in range(7)]
    notchring.insert(3, '')
    beta = ("A, B, B+, C, D, E, E+, F, G, G+, "
            "H, I, J, J+, K, L, M, M+ N, O, O+, "
            "P, Q, R, R+, S, T, T+, U, V, W, W+, "
            "X, Y, Z, Z+").replace(",", "").split()
    val = irandrange(len(beta))
    ringset = [beta[next(val)] for i in range(7)]
    ringset.insert(3, '')
    return rotor, core, ring, notchring, ringset

if __name__ == '__main__':
    for row in make_key():
        print(''.join('{:<3}'.format(x) for x in row))
Output:
1 2 3 4 5 6 7 8 G D A F J L H E 34 31 36 29 4 19 11 3 6 9 7 1 8 5 10 S B+ D X Z+ A M
Starting with 3.6, one can use the secrets module instead of os.urandom
Reply
#5
(Dec-14-2018, 07:20 PM)Gribouillis Wrote: A small training session in my favorite language
#!/usr/bin/env python3
import itertools as itt
import os

def iranduint():
    yield from itt.chain.from_iterable(os.urandom(1024) for k in itt.count())
iranduint = iranduint()

def irandrange(n):
    sz = n.bit_length()
    if sz > 8:
        raise ValueError('Expected value < 256, got', n)
    m = 2 ** sz
    assert((m/2) <= n < m)
    for x in iranduint:
        x %= m
        if x < n:
            yield x
            
def irandchoice(n):
    s = set()
    while True:
        x = next(irandrange(n))
        if x in s:
            continue
        s.add(x)
        yield x

def make_key():
    rotor = [x for x in range(1, 9)]
    alpha = [x for x in "ABCDEFGHIJKL"]
    chx = irandchoice(len(alpha))
    core = [alpha[next(chx)] for i in range(8)]
    g36 = irandrange(36)
    ringset = [1 + next(g36) for i in range(8)]
    g11 = irandchoice(11)
    notchring = [1 + next(g11) for i in range(7)]
    notchring.insert(3, '')
    beta = ("A, B, B+, C, D, E, E+, F, G, G+, "
            "H, I, J, J+, K, L, M, M+ N, O, O+, "
            "P, Q, R, R+, S, T, T+, U, V, W, W+, "
            "X, Y, Z, Z+").replace(",", "").split()
    val = irandrange(len(beta))
    ringset = [beta[next(val)] for i in range(7)]
    ringset.insert(3, '')
    return rotor, core, ringset, notchring, ringset

if __name__ == '__main__':
    for row in make_key():
        print(''.join('{:<3}'.format(x) for x in row))
Starting with 3.6, one can use the secrets module instead of os.urandom

Wooow! Thank you soooooooooooooooooooooooooooooooooooooo much, really, really made my day! I just posted the same request in a forum called Stackoverflow and was voted off topic in about 15 seconds, I was very, very disappointed and just came back here to have a look and found your solution! It works perfectly, could not even dream about a better implementation! Thank you for your time and effort, it's great to know there are still helpful people who don't just say "learn Python and make one yourself" - I truly appreciate your kindness!

One last question - is it possible to add some lines to the code that achieve the following:

When running the program, is it possible to get the program first ask HOW MANY KEYS DO YOU WANT TO GENERATE? The user then enters a number between let's say 1 and 31 and then the program generates that amount of keys. This way, a full, monthly key set can be generated in a few seconds. :-)
Reply
#6
Is it possible to make a small change - there seem to letters in Line 2 (Alphabet Ring Set) instead of numbers (1-36). It looks like Line 2 is the same as Line 4. Would you please be able to change Line 2 so that it generates numbers from 1-36 (instead of letters like Line 4). The same number can occur more than once in Line 2.

Thank you :-)

EDIT: found the reason why Line 2 and Line 4 were identical - same name was given, changed the name of Line 2 and now it's all spot on. :-)
All that I would still like to ask, to please add some code so that the program first asks how many codes I want to generate - so that I can reply with a number between let's say 1 to 31 and so a full month of keys can be done. :-)
Reply
#7
I added two options to the script: -n NUMBER to specify the desired number of keys and -m to allow the letter M in the result
#!/usr/bin/env python3
from argparse import ArgumentParser
import itertools as itt
import os

__version__ = '0.0.2'

def iranduint():
    yield from itt.chain.from_iterable(os.urandom(1024) for k in itt.count())
iranduint = iranduint()

def irandrange(n):
    sz = n.bit_length()
    if sz > 8:
        raise ValueError('Expected value < 256, got', n)
    m = 2 ** sz
    assert((m/2) <= n < m)
    for x in iranduint:
        x %= m
        if x < n:
            yield x
            
def irandchoice(n):
    s = set()
    src = irandrange(n)
    while n:
        x = next(src)
        if x in s:
            continue
        s.add(x)
        n -= 1
        yield x

def make_key(addm):
    rotor = [x for x in range(1, 9)]
    alpha = [x for x in "ABCDEFGHIJKL"]
    if addm: alpha.append('M')
    chx = irandchoice(len(alpha))
    core = [alpha[next(chx)] for i in range(8)]
    g36 = irandrange(36)
    ring = [1 + next(g36) for i in range(8)]
    g11 = irandchoice(11)
    notchring = [1 + next(g11) for i in range(7)]
    notchring.insert(3, '')
    beta = ("A, B, B+, C, D, E, E+, F, G, G+, "
            "H, I, J, J+, K, L, M, M+ N, O, O+, "
            "P, Q, R, R+, S, T, T+, U, V, W, W+, "
            "X, Y, Z, Z+").replace(",", "").split()
    val = irandrange(len(beta))
    ringset = [beta[next(val)] for i in range(7)]
    ringset.insert(3, '')
    return rotor, core, ring, notchring, ringset

def main(cnt, addm):
    for i in range(cnt):
        print()
        for row in make_key(addm):
            print(''.join('{:<3}'.format(x) for x in row))

if __name__ == '__main__':
    parser = ArgumentParser(description="Get new keys")
    parser.add_argument('-n', help="number of keys to generate",
                        default=1, type=int)
    parser.add_argument('-m', help="add letter M",
                        action='store_true')
    ns = parser.parse_args()
    main(ns.n, ns.m)
Quote:I just posted the same request in a forum called Stackoverflow and was voted off topic in about 15 seconds
Yes, I wouldn't have answered this in SO, it's against the rules to give code this way. I do it here because I find it funny to solve this question. I hope it's not homework.
Reply
#8
(Dec-14-2018, 09:23 PM)Gribouillis Wrote: Yes, I wouldn't have answered this in SO, it's against the rules to give code this way. I do it here because I find it funny to solve this question. I hope it's not homework.

Thank you very much man, you are very kind and helpful!

As for SO - fair enough! Didn't know how that forum works, I thought one can just ask for such thing, but I realized in no time that my request was not welcome. :-)
Reply
#9
Quote:Didn't know how that forum works
SO is not exactly a forum, it is a "questions and answers site". It is organized in such a way that as time passes it becomes a gigantic FAQ where almost every technical issue of the language has a solution. Your question is not a technical issue. It is knocked out by design.
Reply
#10
Sorry to be a plague. How should I choose the number of keys and letter M? When running the program by pressing F5, I am not given the choice to select these, the program runs as before.

Figured out. Sometimes it's fun to try and use my brain, it often gets too lazy! Thank you, fantastic program! Just to let you know, this is the cipher machine I will use it with:

http://users.telenet.be/d.rijmenants/en/kl-7sim.htm

Once again, thank you!
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020