willichan

Encryption based on the Enigma machine

4 posts in this topic

#1 ·  Posted (edited)

Back in July, I was working with my Webelo Scouts, discussing things to make with wood. One of them described an Enigma Machine his uncle had built using wood and thumbtacks. Everyone was intrigued, and wanted to know more about the enigma machine. As part of a follow-up, I wrote the following UDF to demonstrate the principles. Please feel free to use this in your scripts, or for demonstration, ... or for just plain curiosity.

I realize the comments are sparse, so if you have any questions, feel free to let me know.

----Edit----

By using a passkey to seed SRandom(), I eliminate the need to store details on each wheel. Random then gives me a reliable sequence of numbers to use for generating wheel data and reflector plates. Since I don't have to store each wheel in the script, I reduce the size of the script, while increasing the possible configurations.

Enigma.au3

#cs ----------------------------------------------------------------------------

    Project Name: Enigma
    Description: Encryption based on Enigma machine
    AutoIt Version: v3.3.6.1
    Author: David Williams (willichan)
    Email: david@optionsintegrated.com
    website: http://optionsintegrated.com
    Company: Options Integrated
    Creation Date: 7/26/2010

#ce ----------------------------------------------------------------------------
#include-once

#cs
    ***  Enigma_Object  ***
    [0][0] = WheelCount
    [0][1] = BaseSeed  ;number representing $basekey, used to seed random()
    [1][0]  [0 - 255]    = Reflector data
    [1][x] = Wheel x data
    [1][x]  [0][0 - 255] = passforward data (0 - 255)
    [1][x]  [0][256]     = starting position (0 - 255)
    [1][x]  [1][0 - 255] = passbackward data (0 - 255)
    [1][x]  [1][256]     = current position  (0 - 255)
#ce

#cs
    ***  WheelDefs  ***
    [0][0] = # of wheels
    [x][0] = wheel x ID number (0 - 2147483647)
    [x][1] = wheel x starting position (0 - 255)
#ce

; +------------------+
; | Public Functions |
; +------------------+

Func _Enigma_Initialize($BaseKey, $WheelDefs = -1, $ReflectorDef = -1)
    Local $Enigma_Object
    Local $WheelCount
    Local $i, $j
    Local $automated = True
    If IsArray($WheelDefs) Then $automated = False
    Local $BaseSeed = _Enigma_Numify($BaseKey)
    SRandom($BaseSeed)
    If $automated Then
        $WheelCount = 4
    Else
        $WheelCount = $WheelDefs[0][0]
    EndIf
    Dim $j[$WheelCount]
    For $i = 1 To $WheelCount
        If $automated Then
            $j[$i - 1] = Random(0, 65535, 1)
        Else
            $j[$i - 1] = $WheelDefs[$i][0]
        EndIf
    Next
    Dim $Enigma_Object[2][$WheelCount + 1]

    $Enigma_Object[0][0] = $WheelCount
    $Enigma_Object[0][1] = $BaseSeed
    If $ReflectorDef < 0 Then
        $Enigma_Object[1][0] = _Enigma_GenReflector(BitXOR($BaseSeed, Random(0, 65535, 1)))
    Else
        $Enigma_Object[1][0] = _Enigma_GenReflector(BitXOR($BaseSeed, $ReflectorDef))
    EndIf
    For $i = 1 To $WheelCount
        $Enigma_Object[1][$i] = _Enigma_GenWheel(BitXOR($BaseSeed, $j[$i - 1]))
        If $automated Then
            _Enigma_SetSubArray($Enigma_Object, Random(0, 255, 1), 1, $i, 0, 256)
            _Enigma_SetSubArray($Enigma_Object, _Enigma_GetSubArray($Enigma_Object, 1, $i, 0, 256), 1, $i, 1, 256)
        Else
            _Enigma_SetSubArray($Enigma_Object, $WheelDefs[$i][1], 1, $i, 0, 256)
            _Enigma_SetSubArray($Enigma_Object, _Enigma_GetSubArray($Enigma_Object, 1, $i, 0, 256), 1, $i, 1, 256)
        EndIf
    Next
    SRandom($Enigma_Object[0][1])
    Return $Enigma_Object
EndFunc   ;==>_Enigma_Initialize

Func _Enigma_Reset(ByRef $Enigma_Object)
    Local $i
    For $i = 1 To $Enigma_Object[0][0]
        _Enigma_SetSubArray($Enigma_Object, _Enigma_GetSubArray($Enigma_Object, 1, $i, 0, 256), 1, $i, 1, 256)
    Next
    SRandom($Enigma_Object[0][1])
EndFunc   ;==>_Enigma_Reset

Func _Enigma_Crypt(ByRef $Enigma_Object, $data, $reset = True)
    Local $i
    Local $RetData
    If $reset Then _Enigma_Reset($Enigma_Object)
    $RetData = ""
    For $i = 1 To StringLen($data)
        $RetData &= Chr(_Enigma_CryptChar($Enigma_Object, Asc(StringMid($data, $i, 1))))
    Next
    Return $RetData
EndFunc   ;==>_Enigma_Crypt

; +-------------------+
; | Private Functions |
; +-------------------+

Func _Enigma_GetSubArray(ByRef $MainArray, $sub1, $sub2, $sub3 = -1, $sub4 = -1)
    Local $temp
    $temp = $MainArray[$sub1][$sub2]
    Switch @NumParams
        Case 3
            Return $temp
        Case 4
            Return $temp[$sub3]
        Case 5
            Return $temp[$sub3][$sub4]
    EndSwitch
EndFunc   ;==>_Enigma_GetSubArray

Func _Enigma_SetSubArray(ByRef $MainArray, $value, $sub1, $sub2, $sub3 = -1, $sub4 = -1)
    Local $temp
    $temp = $MainArray[$sub1][$sub2]
    Switch @NumParams
        Case 4
            $temp = $value
        Case 5
            $temp[$sub3] = $value
        Case 6
            $temp[$sub3][$sub4] = $value
    EndSwitch
    $MainArray[$sub1][$sub2] = $temp
EndFunc   ;==>_Enigma_SetSubArray

Func _Enigma_CryptChar(ByRef $Enigma_Object, $character)
    Local $i
    Local $RetData = $character
    For $i = 1 To $Enigma_Object[0][0]
        $RetData = _Enigma_GetSubArray($Enigma_Object, 1, $i, 0, $RetData)
    Next
    $RetData = _Enigma_GetSubArray($Enigma_Object, 1, 0, $RetData)
    For $i = $Enigma_Object[0][0] To 1 Step -1
        $RetData = _Enigma_GetSubArray($Enigma_Object, 1, $i, 1, $RetData)
    Next
    _Enigma_Rotate($Enigma_Object)
    Return $RetData
EndFunc   ;==>_Enigma_CryptChar

Func _Enigma_Rotate(ByRef $Enigma_Object, $WheelID = 1)
    _Enigma_SetSubArray($Enigma_Object, _Enigma_GetSubArray($Enigma_Object, 1, $WheelID, 1, 256) + 1, 1, $WheelID, 1, 256)
    If _Enigma_GetSubArray($Enigma_Object, 1, $WheelID, 1, 256) > 255 Then
        _Enigma_SetSubArray($Enigma_Object, 0, 1, $WheelID, 1, 256)
        If $WheelID < $Enigma_Object[0][0] Then _Enigma_Rotate($Enigma_Object, $WheelID + 1)
    EndIf
EndFunc   ;==>_Enigma_Rotate

Func _Enigma_GenWheel($Seed)
    Local $Wheel[2][257]
    Local $remaining[256]
    Local $i, $j
    SRandom($Seed)
    For $i = 0 To 255
        $remaining[$i] = 1
    Next
    For $i = 0 To 255
        $j = Random(0, 255, 1)
        While $remaining[$j] = -1
            $j += 1
            If $j > 255 Then $j = 0
        WEnd
        $Wheel[0][$i] = $j
        $Wheel[1][$j] = $i
        $remaining[$j] = -1
    Next
    Return $Wheel
EndFunc   ;==>_Enigma_GenWheel

Func _Enigma_GenReflector($Seed)
    Local $Reflector[256]
    Local $i, $j
    SRandom($Seed)
    For $i = 0 To 255
        $Reflector[$i] = $i
    Next
    For $i = 0 To 255
        If $Reflector[$i] = $i Then
            $j = Random(0, 255, 1)
            While $Reflector[$j] <> $j
                $j += 1
                If $j > 255 Then $j = 0
            WEnd
            $Reflector[$i] = $j
            $Reflector[$j] = $i
        EndIf
    Next
    Return $Reflector
EndFunc   ;==>_Enigma_GenReflector

Func _Enigma_Numify($data)
    Local $res[8] = [0, 0, 0, 0, 0, 0, 0, 0]
    Local $clipping, $i, $result
    While StringLen($data) > 0
        $clipping = StringSplit(StringRight("        " & $data, 8), "", 2)
        For $i = 0 To 7
            $res[$i] = BitXOR($res[$i], Asc($clipping[$i]))
        Next
        If StringLen($data) < 8 Then
            $data = ""
        Else
            $data = StringLeft($data, StringLen($data) - 8)
        EndIf
    WEnd
    $result = 0
    For $i = 0 To 6
        $result += $res[$i]
        $result *= 256
    Next
    $result += $res[7]
    $result = BitAND($result, 2147483647)
    If BitAND($res[0], 128) > 0 Then $result = -1 * $result
    Return $result
EndFunc   ;==>_Enigma_Numify

Here is a sample file that uses it.

sample.au3

#include <Enigma.au3>

$mykey = "Zippity Doo Da" ;my super-secret passkey
Dim $WD[5][2] = [[4,4],[5000,200],[101,201],[3110,202],[11,203]] ;the wheel data array
$RD = 65042 ;the reflector plate

$a = "I picked out my own four-wheeler." ;the original string
$crypter = _Enigma_Initialize($mykey, $WD, $RD) ;get the enigma object
$b = _Enigma_Crypt($crypter, $a) ;Encrypt the original string
$c = _Enigma_Crypt($crypter, $b) ;Decrypt the encrypted string

MsgBox(0, "test1", "'" & $a & "'" & @CRLF & _
                  "'" & $b & "'" & @CRLF & _
                  "'" & $c & "'")

$mykey = "Bibbidy Bobbidy Boo!" ;my super-secret passkey
$a = "You pick out the wheels this time." ;the original string

$crypter = _Enigma_Initialize($mykey) ;get the enigma object
$b = _Enigma_Crypt($crypter, $a) ;Encrypt the original string
$c = _Enigma_Crypt($crypter, $b) ;Decrypt the encrypted string

MsgBox(0, "test2", "'" & $a & "'" & @CRLF & _
                  "'" & $b & "'" & @CRLF & _
                  "'" & $c & "'")
Edited by willichan

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

It looks interesting. I was wondering one thing though. That is whether using all 256 ascII characters is reliable, or not. I haven't fully examined what is happening with the code, so perhaps my concern is unfounded. I thought I would ask about it anyway. Are you including the NUL character, and can you do that?

Edit

When I once tried something similar to this, I avoided using some of the control characters, because I wasn't sure of the consequences.

Edited by czardas

Share this post


Link to post
Share on other sites

I was wondering one thing though. That is whether using all 256 ascII characters is reliable, or not.

When I once tried something similar to this, I avoided using some of the control characters, because I wasn't sure of the consequences.

If you are planning on displaying the encrypted output (like the demo does), then no, it isn't stable. You would have to retool it to work only with displayable characters.

If you are working with files, then yes, it works fine. When you are dealing with binary data, the NUL character (ASCII 0) has to be taken into account. I wrote this to handle the full ASCII 0-255 range.

I'll think about making a displayable characters only version.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Okay, thanks for the insight. I remember avoiding using them, just to be on the safe side; which is the reason it occured to me to ask. ;)

Edited by czardas

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now