SecretCipher - Secret Messages/Concealed Passwords within a string

Post your working scripts, libraries and tools for AHK v1.1 and older
Xion
Posts: 1
Joined: 28 Feb 2018, 16:10

SecretCipher - Secret Messages/Concealed Passwords within a string

02 Mar 2018, 15:35

Thought it was an interesting concept for secret messages, or for my original purpose allowing you to use strong passwords without technically having to remember said password. It's kind of simple(ish) once you understand how the special keys work, depending on which version you use Simple or Complex both have different options, see below for a better description. Anyways the way it works is you input a text string and then you input some numbers and it will retrieve whatever character is at the numbers position within the text string. The idea is that a supposed attacker probably isn't going to know what/where you are getting your string from let alone its starting and ending position, or if you're even using one string you could combine strings from multiple sources.

Simple: Outputs as is, the only extra option available is for adding a space to your calculated string, no options for changing between uppercase and lowercase or adding a literal number or symbol, the only way to get a number or symbol in the calculated result is if it's in your Input Text String.

Complex: Output with options, has options for adding a space, changing between uppercase and lowercase, adding literal numbers and symbols to the output, convert numbers to symbols or vice-versa from the Input Text String.

Special Characters (These characters can easily be changed in the script)
SpaceKey = xx (Both versions, Used if you want to output an actual space)
NumberSplitKey = A_SPACE (Both versions, Separates your single number input string into multiple individual number strings)
EscapeKey = / (Complex Only, Used if you want to output a number or symbol)
LowercaseKey = _ (Complex Only, Used if you want to output the character as lowercase)
UppercaseKey = - (Complex Only, Used if you want to output the character as uppercase)
NoOutputKey1 = (Both versions, One of three characters that can be used to override the output, outputs nothing for that number if the character(s) are found somewhere beside it. Disabled when no character is assigned)
NoOutputKey2 =
NoOutputKey3 =

SecretCipher.ahk
Now I am no expert programmer, noobish with AHK, So I can guarantee you my code is not the most efficient way to do what I want it to do, I'm sure it's quite messy looking, but what I have works. If someone wants to clean up my code, improve upon it, or add new features or whatever then by all means go right ahead.

Code: Select all


; Header ==============================================================================================================
; Name .........: Secret Cipher
; Description ..: Create a code/cipher that can be used to create/use strong passwords or just make a secret message
; AHK Version ..: 1.1.26.00
; Language .....: English (en-US)
; Author .......: Xion
; =====================================================================================================================
; 0 will output the last character in your string, unless there is an escape character in front in that case it will treat it as the literal number 0 or the symbol tied to it
; Any number that is higher than the length of your string will not have an output, was going to implement something that prevents this but then got to thinking this could provide added security having false numbers in your number key. 
; A supposed attacker probably isn't going to know what/where you are getting your string from let alone its starting and ending position.


#SingleInstance, Force
#NoEnv

SimpleVersion = 1          ; 1 = Option that is used by default, Radio button is checked
ComplexVersion = 0         ; 0 = Option not used by default, but can be toggled in the gui window, Radio button is not checked
EscapeKey = /              ; The Escape character to use if you want a literal number or its associated symbol to output, Example using the default character: -/2 _/2 outputs as @2
LowercaseKey = _           ; The character to use if you want the output to be lowercase
UppercaseKey = -           ; The character to use if you want the output to be uppercase
NumberSplitKey := A_SPACE  ; The character used to split your number key string, If you want to use a different character that isn't a variable, like "#", make sure to put quotes around it. And if using a letter know that it is case-sensitive.
SpaceKey = xx              ; The character used if you want a space in your calculated string
NoOutputKey1 =             ; Disabled when no character is assigned, One of three characters that can be used to override the output, outputs nothing for that number if the character(s) are found somewhere beside each number
NoOutputKey2 = 
NoOutputKey3 = 

NoOutputDisabled1 = False  ; These three variables are used alongside the NoOutputKey variables, don't worry about changing these
NoOutputDisabled2 = False
NoOutputDisabled3 = False

; DO NOT CHANGE THE FIRST 10 CHARACTERS IN THE SpecialChar_Array BELOW, DOING SO WILL BREAK CERTAIN FUNCTIONALITY, EVERYTHING AFTER "(" IS OK TO CHANGE
SpecialChar_Array := [")", "!", "@", "#", "$", "%", "^", "&", "*", "(", "?", "~", "``", "-", "_", "+", "=", "[", "]", "{", "}", "\", "/", "|", ";", ":", "'", """", ",", ".", "<", ">"]     ; Used in the complex version, these are the special characters that output if you use an uppercase literal number, Example: -/1 outputs as ! and -/2 outputs as @

Gui, Font, s10, Verdana
Gui, Add, Edit, x32 y43 w330 h75 vTextString
Gui, Add, Edit, x32 y173 w330 h45 vNumberString
Gui, Add, Edit, x32 y272 w330 h45 ReadOnly vCalculatedString

Gui, Font, s12, Verdana
Gui, Add, Text, x32 y19 w330 h20, Text String Input:
Gui, Add, Text, x32 y149 w330 h20, Number Key Input:
Gui, Add, Text, x32 y248 w330 h20, Calculated String:

Gui, Font, s10, Verdana
Gui, Add, Text, x50 y332 w330 h20, Version to use:
Gui, Add, Radio, x161 y330 w60 h22 Checked%SimpleVersion% vSimpleIsChecked, Simple
Gui, Add, Radio, x232 y330 w80 h22 Checked%ComplexVersion% vComplexIsChecked, Complex
Gui, Add, Button, x0 y366 w393 h40 , Calculate

Gui, Show, h406 w393, Secret Ciphering
If (NoOutputKey1 == "")
{
    NoOutputDisabled1 = True
}
If (NoOutputKey2 == "")
{
    NoOutputDisabled2 = True
}
If (NoOutputKey3 == "")
{
    NoOutputDisabled3 = True
}
Return



GuiClose:
ExitApp

ButtonCalculate:
FinalResult =              ; CLEAR THE RESULT VARIABLE
GuiControlGet, TextString
GuiControlGet, NumberString
GuiControlGet, SimpleIsChecked
GuiControlGet, ComplexIsChecked
Number_Array := StrSplit(NumberString, NumberSplitKey)             ; SPLIT NUMBERS INTO SEPERATE VARIABLES
StringReplace, FinalTextString, TextString, %A_SPACE%,, All       ; REMOVE BLANK SPACES FROM THE TEXT STRING

If (SimpleIsChecked == 1 && ComplexIsChecked == 0)
{
    Goto, Simple
}
Else If (SimpleIsChecked == 0 && ComplexIsChecked == 1)
{
    Goto, Complex
}

;===============================================================================================================
Simple:
;===============================================================================================================

Loop % Number_Array.Length()        ; LOOP, DETERMINE WHAT CHARACTER TO USE FOR EACH NUMBER
{
    FullNumberValue := SubStr(Number_Array[A_Index], 1)

    If (NoOutputDisabled1 == "False")       ; VALID CHARACTER WAS ASSIGNED TO VARIABLE
    {
        CheckNoOutput := RegExMatch(FullNumberValue, NoOutputKey1)     ; CHECK IF CHARACTER EXISTS IN NUMBER KEY
        If (CheckNoOutput > 0)      ; EXISTS, STOP THE CURRENT LOOP AND SKIP THIS INDEX
        {
            Continue
        }
    }
    If (NoOutputDisabled2 == "False")       ; VALID CHARACTER WAS ASSIGNED TO VARIABLE
    {
        CheckNoOutput := RegExMatch(FullNumberValue, NoOutputKey2)     ; CHECK IF CHARACTER EXISTS IN NUMBER KEY
        If (CheckNoOutput > 0)      ; EXISTS, STOP THE CURRENT LOOP AND SKIP THIS INDEX
        {
            Continue
        }
    }
    If (NoOutputDisabled3 == "False")       ; VALID CHARACTER WAS ASSIGNED TO VARIABLE
    {
        CheckNoOutput := RegExMatch(FullNumberValue, NoOutputKey3)     ; CHECK IF CHARACTER EXISTS IN NUMBER KEY
        If (CheckNoOutput > 0)      ; EXISTS, STOP THE CURRENT LOOP AND SKIP THIS INDEX
        {
            Continue
        }
    }


    CheckSpaceExist := RegExMatch(FullNumberValue, SpaceKey)

    If (CheckSpaceExist > 0)       ; CHECKS FOR YOUR SPACE CHARACTER(S) IF EXISTS ADD A SPACE, THE SPACE CHARACTER(S) OVERRIDE ALL EXCEPT THE NO OUTPUT KEYS SO SOMETHING LIKE -xx4 OR _/4xx WILL OUTPUT A SPACE AND NO OTHER CHARACTER
    {
        FinalResult = %FinalResult%%A_SPACE%a      ; COMPILE THE RESULTS
        StringTrimRight, FinalResult, FinalResult, 1   ; COULDN'T ADD THE SPACE TO THE END WITHOUT HAVING TO PLACE A CHARACTER AFTER IT, THIS WAS THE ONLY WAY I COULD FIGURE OUT
        Continue        ; STOP THE CURRENT LOOP AND CONTINUE TO THE NEXT INDEX
    }

    FixedNumberValue := RegExReplace(FullNumberValue, "i)[^0-9]")
    ;msgbox, %FixedNumberValue%

    If FixedNumberValue is Space        ; ERROR HANDLER: TRIGGER IF THERE IS AN UNSUPPORTED CHARACTER IN THE NUMBER KEY
    {
        Continue         ; IT IS NOT SUPPORTED SO STOP THE CURRENT LOOP AND SKIP THE CURRENT INDEX
    }
    
    NewCharacter := SubStr(FinalTextString, FixedNumberValue, 1)        ; RETRIEVE CHARACTER FROM TEXT STRING
    FinalResult = %FinalResult%%NewCharacter%         ; COMPILE THE RESULTS
}

GuiControl,, CalculatedString, %FinalResult%      ; SHOW THE RESULTS
Return


;===============================================================================================================
Complex:
;===============================================================================================================

Loop % Number_Array.Length()        ; LOOP, DETERMINE WHAT CHARACTER(S) TO USE FOR EACH NUMBER
{
    FullNumberValue := SubStr(Number_Array[A_Index], 1)

    If (NoOutputDisabled1 == "False")       ; VALID CHARACTER WAS ASSIGNED TO VARIABLE
    {
        CheckNoOutput := RegExMatch(FullNumberValue, NoOutputKey1)     ; CHECK IF CHARACTER EXISTS IN NUMBER KEY
        If (CheckNoOutput > 0)      ; EXISTS, STOP THE CURRENT LOOP AND SKIP THIS INDEX
        {
            Continue
        }
    }
    If (NoOutputDisabled2 == "False")       ; VALID CHARACTER WAS ASSIGNED TO VARIABLE
    {
        CheckNoOutput := RegExMatch(FullNumberValue, NoOutputKey2)     ; CHECK IF CHARACTER EXISTS IN NUMBER KEY
        If (CheckNoOutput > 0)      ; EXISTS, STOP THE CURRENT LOOP AND SKIP THIS INDEX
        {
            Continue
        }
    }
    If (NoOutputDisabled3 == "False")       ; VALID CHARACTER WAS ASSIGNED TO VARIABLE
    {
        CheckNoOutput := RegExMatch(FullNumberValue, NoOutputKey3)     ; CHECK IF CHARACTER EXISTS IN NUMBER KEY
        If (CheckNoOutput > 0)      ; EXISTS, STOP THE CURRENT LOOP AND SKIP THIS INDEX
        {
            Continue
        }
    }


    CheckSpaceExist := RegExMatch(FullNumberValue, SpaceKey)

    If (CheckSpaceExist > 0)       ; CHECKS FOR YOUR SPACE CHARACTER(S) IF EXISTS ADD A SPACE, THE SPACE CHARACTER(S) OVERRIDE ALL EXCEPT THE NO OUTPUT KEYS SO SOMETHING LIKE -xx4 OR _/4xx WILL OUTPUT A SPACE AND NO OTHER CHARACTER
    {
        FinalResult = %FinalResult%%A_SPACE%a      ; COMPILE THE RESULTS
        StringTrimRight, FinalResult, FinalResult, 1   ; COULDN'T ADD THE SPACE TO THE END WITHOUT HAVING TO PLACE A CHARACTER AFTER IT, THIS WAS THE ONLY WAY I COULD FIGURE OUT
        Continue        ; STOP THE CURRENT LOOP AND CONTINUE TO THE NEXT INDEX
    }

    CheckNumbersExist := RegExMatch(FullNumberValue, "[0-9]")

    If (CheckNumbersExist == 0)       ; ERROR HANDLER: NO NUMBERS EXIST
    {
        Continue        ; STOP THE CURRENT LOOP AND SKIP THIS INDEX
    }

    TempNumberValue := RegExReplace(FullNumberValue, "i)[^" UppercaseKey "" LowercaseKey "" EscapeKey "0-9]")        ; REMOVE UNSUPPORTED CHARACTERS
    CaseKeyPos := RegExMatch(TempNumberValue, "[" LowercaseKey "" UppercaseKey "]")         ; GET POSITION OF THE FIRST OCCURANCE OF EITHER "LowercaseKey" OR "UppercaseKey"
    ;msgbox, %TempNumberValue%

    If (CaseKeyPos == 1)      ; SUPPORTED, CASE KEY IS THE FIRST CHARACTER
    {
        RemoveExtraCase := RegExReplace(TempNumberValue, "[" LowercaseKey "" UppercaseKey "]",,,, 2)     ; REMOVE ALL ADDITIONAL CASE CHARACTERS AFTER THE FIRST OCCURRENCE
    }
    Else                ; NOT SUPPORTED, CASE KEY IS NOT THE FIRST CHARACTER
    {
        Continue      ; STOP THE CURRENT LOOP AND SKIP THIS INDEX
    }

    ;msgbox, Extra Case Characters Removed: %RemoveExtraCase%
    EscapeKeyPos := InStr(RemoveExtraCase, EscapeKey)

    If (EscapeKeyPos == 2)       ; SUPPORTED, ESCAPE KEY IS THE SECOND CHARACTER
    {
        FixedNumberValue := RegExReplace(RemoveExtraCase, "[" EscapeKey "]",,,, 3)   ; REMOVE EXTRA ESCAPE CHARACTERS AFTER THE FIRST OCCURRENCE 
    }
    Else       ; SUPPORTED, ESCAPE KEY IS NOT SECOND CHARACTER, ASSUME NON-LITERAL NUMBER
    {
        FixedNumberValue := RegExReplace(RemoveExtraCase, "[" EscapeKey "]")    ; REMOVE ALL ESCAPE CHARACTERS
    }

    ;msgbox, Fixed Number: %FixedNumberValue%
    DetermineCase := SubStr(FixedNumberValue, 1, 1)     ; GET FIRST CHARACTER, CASE CHARACTER
    IsLiteralNumber := SubStr(FixedNumberValue, 2, 1)   ; GET SECOND CHARACTER, USED TO DETERMINE IF ESCAPE CHARACTER IS USED

    If FixedNumberValue is Space        ; ERROR HANDLER: TRIGGER IF THERE IS AN UNSUPPORTED CHARACTER IN THE NUMBER KEY
    {
        Continue                 ; IT IS NOT SUPPORTED SO STOP THE CURRENT LOOP AND SKIP THE CURRENT INDEX
    }

    If (IsLiteralNumber == EscapeKey)       ; TRUE, TREAT AS LITERAL NUMBER
    {
        StringTrimLeft, FinalNumber, FixedNumberValue, 2    ; REMOVE CASE AND ESCAPE CHARACTER, GET THE NUMBER BY ITSELF
        ;StringTrimRight, FinalNumber, LeftTrimNum, 1
    }
    Else                                   ; FALSE, RETRIEVE CHARACTER FROM TEXT STRING
    {
        StringTrimLeft, FinalNumber, FixedNumberValue, 1    ; REMOVE CASE CHARACTER, GET THE NUMBER BY ITSELF
        NewCharacter := SubStr(FinalTextString, FinalNumber, 1)    ; RETRIEVE CHARACTER
    }

    ;msgbox, Final Number: %FinalNumber%
    StringCharIsSymbol:= RegExMatch(NewCharacter, "[\)!@#\$%\^&\*\(]")
    StringCharIsNumber := RegExMatch(NewCharacter, "[0-9]")

    If (DetermineCase == LowercaseKey)        ; OUTPUT AS LOWERCASE
    {
        If (IsLiteralNumber == EscapeKey)   ; OUTPUT LITERAL NUMBER
        {
            NewCharacter := FinalNumber
        }
        Else                    ; OUTPUT CHARACTER FROM STRING AS LOWERCASE
        {
            If (StringCharIsSymbol > 0) ; TRUE, IS A SUPPORTED SYMBOL, CONVERTS SYMBOLS TO NUMBERS, SPECIFICALLY ONES TIED TO THE NUMBER KEYS 0-9
            {
                Loop 10     ; LOOP THROUGH EACH SYMBOL IN THE ARRAY AND DETERMINE/OUTPUT ITS NUMBER
                {
                    If (NewCharacter == SpecialChar_Array[A_Index])
                    {
                        NewCharacter := A_Index-1
                        Break
                    }
                }
            }
            Else
            {
            StringLower, NewCharacter, NewCharacter
            }
        }
    }


    If (DetermineCase == UppercaseKey)           ; OUTPUT AS UPPERCASE
    {
        If (IsLiteralNumber == EscapeKey)   ; OUTPUT SPECIAL CHARACTER TIED TO THAT LITERAL NUMBER
        {
            If (FinalNumber <= SpecialChar_Array.Length()-1)               ; DETERMINE IF NUMBER IS SUPPORTED, IF SO OUTPUT
            {
                NewCharacter := SpecialChar_Array[FinalNumber+1]     ; THE ARRAY INDEX STARTS AT 1 RATHER THAN 0, 1 IS ADDED TO COMPENSATE
            }
            Else                  ; ERROR HANDLER: NO OUTPUT IF NUMBER IS HIGHER THAN 31, ARRAY ONLY HAS 32 ITEMS
            {
                Continue
            }
        }
        Else                    ; OUTPUT CHARACTER FROM STRING AS UPPERCASE
        {
            If (StringCharIsNumber > 0)   ; TRUE, IS A SUPPORTED NUMBER, CONVERTS NUMBERS TO SYMBOLS
            {
                NewCharacter := SpecialChar_Array[NewCharacter+1] 
            }
            Else
            {
                StringUpper, NewCharacter, NewCharacter
            }
        }
    }

    FinalResult = %FinalResult%%NewCharacter%       ; COMPILE THE RESULTS
}

GuiControl,, CalculatedString, %FinalResult%      ; SHOW THE RESULTS
Return

It's hard to describe how it all works, So I feel it's better to just show a lot of examples.


Example 1:

Input Text String: abcdefghijklmnopqrstuvwxyz

Number Keys and their Outputs:
Simple Version:

8 5 12 12 15 xx 23 15 18 12 4 = hello world


Complex Version:

_1 = a
Lowercase

-1 = A
Uppercase

-/1 = !
Literal Symbol

_/1 = 1
Literal Number

-8 _5 _12 _12 _15 xx -23 _15 _18 _12 _4 -/1 = Hello World!


Example 2:

Input Text String: This is a test! 123 (Note: All spaces get removed from the input text string so if you are manually counting to figure out what numbers to use make sure to skip over the spaces)

Number Keys and their Outputs:
Simple Version:

2 4 4 1 12 14 3 = hssT!2i

aw-#rb2fg 4@vx sgfs%b 4sfse* 1sdfv <12> 14 3 = hssT!2i

2 4 4 xx 1 12 14 3 = hss T!2i
xx is the character I assigned by default if you want to use a space


Complex Version:

-2 -4 _4 _1 -12 -14 -3 = HSst!@I

-2 -4 xx _4 _1 -1xx2 -14 -3 = HS st @I
The space character overrides everything no matter where you put it, with the exception of NoOutputKey 1-3 which truly overrides everything including the space character

-/4 _/4 -5 -/1 -/2 _15 -15 _0 -0 = $4I!@3#3#
Zero will output the last character in your string

ads-fwk/4a argw sdf_/adg4rox s-adew5///--_ -/1 -/2 _15 ---___-15 _0 -0 = $4I!@3#3#
You can kind of go crazy with it and make it look like a whole lot of nothing, more so if you change the "Split" character from a space to something else and make it look like one big garbled string, maybe that's what you are going for.

_1 _2 _999 _4 _0 -0 = ths3#
Any number higher than the length of your string won't have an output unless used literally with the escape character

/_/3 = No Output, If the escape character is the first character. With one exception, if the space character is included somewhere as seen below.

_/3 /_2 /_xx2 _/4 = 3 4
The one exception whenever the escape is the first character

asd@s%dfg/_/3 = No Output, The escape character is still the first character, my code will remove all letters and symbols that aren't either the Escape, Uppercase, or Lowercase character and detect the escape character as being first

_/999 -/922 -/0 _/0 = 999)0
-/922 has no output because it is outside the bounds of my special character array (symbols) there is a total of 32 characters currently, so anything between -/0 and -/31 is accepted and anything higher will have no output. Unless of course you add/remove characters from that array, my code is set up to handle that. Though you shouldn't change the first 10 characters I set it up to match the symbols tied to the number keys on the keyboard and if changed the conversion from number to symbol and vice-versa from your input text string won't work as intended.

-12 _12 -13 _14 -14 = !1!2@
Example showing the conversion symbols to numbers and numbers to symbols

-__--_2 __-_2 -1/0 5_ = HhS
My code will use the first uppercase or lowercase character it encounters and remove all others if there is multiple, escape key is handled the same way. The exception being that if the first uppercase, lowercase, or escape character it encounters is behind the first number encountered
User avatar
Gio
Posts: 1247
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: SecretCipher - Secret Messages/Concealed Passwords within a string

06 Mar 2018, 08:16

Hello Xion.

Welcome to the AutoHotkey Community forums.

This is an interesting tool. Good passwords are both hard to guess (by any third-party) and easy to remember (by yourself). If one can input two easy to remeber strings (one literal, one numeric) and use the code above, he/she should retrieve a hard to guess output.

I had some trouble using it at first though. I set my literal string as "abcdefghi" and my numeric input as "888333". It both did not give me any results and did not output any error warnings. Took a while to figure out i had to input the numbers as "8 8 8 3 3 3" based on the examples. I suppose some error warnings for cases like this would be a good addition to guide new users into correct usage.

Code: Select all

...
ButtonCalculate:
FinalResult =              ; CLEAR THE RESULT VARIABLE
GuiControlGet, TextString
GuiControlGet, NumberString
GuiControlGet, SimpleIsChecked
GuiControlGet, ComplexIsChecked
Number_Array := StrSplit(NumberString, NumberSplitKey)             ; SPLIT NUMBERS INTO SEPERATE VARIABLES
StringReplace, FinalTextString, TextString, %A_SPACE%,, All       ; REMOVE BLANK SPACES FROM THE TEXT STRING

IfNotInString, NumberString, %A_Space% ; This is an example.
{
	msgbox, 0x10, Error, The numeric input must be separated by spaces.
	Return
}
...
Thanks for sharing.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: Chunjee and 68 guests