Skip to content

Instantly share code, notes, and snippets.

@AdamQuixote
Created March 11, 2025 14:40
Show Gist options
  • Select an option

  • Save AdamQuixote/80907662873375ea4b16fc7a657b3293 to your computer and use it in GitHub Desktop.

Select an option

Save AdamQuixote/80907662873375ea4b16fc7a657b3293 to your computer and use it in GitHub Desktop.
Simple python rotational cipher for recovery keys in the format ABCD-1234-XXXX.. (format-independent, only uses A-Z and 0-9)
import sys
import time
def get_shift(pin_char):
"""
Returns the numeric shift value for a given PIN character.
Digits are taken as their integer value.
Letters use their position in the alphabet (A=1, B=2, etc.).
"""
if pin_char.isdigit():
return int(pin_char)
elif pin_char.isalpha():
return ord(pin_char.upper()) - ord('A') + 1
else:
return 0
def rotate_char(c, shift):
"""
Rotates a single character by the given shift amount.
For digits, rotation is modulo 10.
For letters, rotation is modulo 26 (only uppercase letters).
Non-alphanumeric characters (like '-') are returned unchanged.
"""
if c.isdigit():
new_digit = (int(c) + shift) % 10
return str(new_digit)
elif c.isalpha():
new_index = (ord(c) - ord('A') + shift) % 26
return chr(new_index + ord('A'))
else:
return c
def animate_rotation(c, shift, delay=0.2):
"""
Animates the rotation of a character in place.
If shift is positive, rotates forward; if negative, rotates backward.
Intermediate rotation steps are shown using backspaces.
"""
if shift == 0:
print(c, end="", flush=True)
elif shift > 0:
for i in range(1, shift + 1):
intermediate = rotate_char(c, i)
print(intermediate, end="", flush=True)
time.sleep(delay)
if i != shift:
print("\b", end="", flush=True)
else: # shift is negative
for i in range(-1, shift - 1, -1): # e.g., if shift is -3, i takes -1, -2, -3.
intermediate = rotate_char(c, i)
print(intermediate, end="", flush=True)
time.sleep(delay)
if i != shift:
print("\b", end="", flush=True)
def main():
# Get inputs from the user.
recovery_key = input("Enter recovery key (format xxxx-xxxx): ").strip().upper()
pin = input("Enter PIN (digits and/or letters, prefix with '-' for decryption): ").strip()
# Check if PIN starts with '-' indicating decryption mode.
decrypt = False
if pin.startswith("-"):
decrypt = True
pin = pin[1:] # Remove the minus sign for processing.
# Convert the PIN into a list of shift values (skip non-alphanumeric characters)
shifts = [get_shift(c) for c in pin if c.isalnum()]
if not shifts:
print("PIN must contain at least one alphanumeric character.")
sys.exit(1)
mode = "Decrypting" if decrypt else "Encrypting"
print(f"\n{mode} rotational cipher:")
final_key = ""
pin_index = 0
# Process each character in the recovery key.
for c in recovery_key:
if c.isalnum():
base_shift = shifts[pin_index % len(shifts)]
# Use negative shift if decrypting.
current_shift = -base_shift if decrypt else base_shift
animate_rotation(c, current_shift)
final_key += rotate_char(c, current_shift)
pin_index += 1
else:
print(c, end="", flush=True)
final_key += c
print() # Move to a new line after printing the key.
if decrypt:
print("Deciphered key:", final_key)
else:
print("Ciphered key:", final_key)
if __name__ == "__main__":
main()
@AdamQuixote
Copy link
Author

AdamQuixote commented Mar 11, 2025

Currently, any non a-z, 0-9 special character (including accented letters) is treated as a separator. It would be easy to modify to include special characters by using "elif str(c) in ["$", "^"], adding a gvar or param and using that to check whether an object should be iterated through instead (probably a list) - this would allow custom rotations, and essentially turn the script into a key.

Good as a proof of concept, and probably only usable in online contexts where queries are limited. In an offline context, a true encryption function would be essential.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment