Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {{
- ─────────────────────────────────────────────────
- File: BadgeDriver_v1_0.spin
- Version: 1.0
- Copyright (c) 2016 Tymkrs
- See end of file for terms of use.
- Author: Whisker
- ─────────────────────────────────────────────────
- }}
- {
- HISTORY:
- This driver is made as an example for using the Badge Bug to drive a Cyphercon2016 badge over a serial port
- USAGE:
- • Desolder / remove the 0 Ohm default resistors from the back of the badge
- • Install Badge Bug
- • Flash this firmware to the Badge Bug (via Propeller Tool & Prop Plug, etc.)
- • Use a serial terminal emulator and a usb ttl serial cable to talk to Badge Bug at 115200 baud
- • Geekcred for not using an emulator (I got it running @300 baud over an acoustic coupler, just saying)
- }
- {{ CypherTTY
- A minimal 3 bit character encoding standard designed for the Cyphercon 2016 Badge
- 000 > > > > > >
- 001 SP 3 , N U B
- 010 E 4 ? S M V
- 011 T 5 ! H W K
- 100 . 6 " R F J
- 101 0 7 A D G X
- 110 1 8 O L Y Q
- 111 2 9 I C P Z
- Encoding characters into a bit stream:
- A message always starts from the first column.
- If the desired character exists on this column, note down the indicated 3 bit value from the matrix.
- If not, a value of 000 shifts to the next column.
- This is a 'Column Shift' character, and is unprintable.
- Shifting from the last column wraps back to the first column.
- Special cases when CypherTTY encoding a ciphertext binary stream:
- After encryption, if the last character in the ciphertext is a Column Shift, notate this with a "+" character.
- Replace any run of six Column Shift characters with a "=" character.
- These rules avoid two situations where, without them,
- it would be possible to encode a stream of bits into a string that would decode to a different stream of bits.
- Which, while hilarious ... makes for a very short game of telephone.
- }}
- Con
- _clkmode = xtal1 + pll16x 'Tell the hardware to run at 80Mhz
- _xinfreq = 5_000_000 '(important for solid serial communications)
- Obj
- fds : "FullDuplexSerial" 'Include software UART serial driver
- Var
- long P 'Column pointer while CypherTTY encoding
- long oP 'Column pointer while CypherTTY decoding
- long IsLast 'Flag for catching a hanging Column Shift character while CypherTTY encoding
- long FullLoop 'Counter for catching a run of six Column Shift characters while CypherTTY encoding
- long SR_ 'Variable for storing the working copy of the linear feedback shift register
- long BackupSR_ 'Variable for storing the user entered seed for the linear feedback shift register
- long BufferPointer 'Pointer to current position in the message buffer while user enters data and upper bound while CypherTTY encoding
- byte Buffer[1024] 'Byte array buffer for storing the user entered message (you could make this larger if you need to)
- Pub Main 'Program enters here
- Init 'Call the initialization subroutine
- 'Main Program Loop, this repeats over and over
- repeat
- ScanConsole 'Call the ScanConsole subroutine, execution does not return to here until the console scanner is finished
- waitcnt((clkfreq / 100) + cnt) 'Pause for 10ms
- Pub Init | Index
- dira[0..23] := %11111111_11111000_11100000 'Set the direction of the lower 24 input / output pins.
- 'We're not using all of these but some of the unused pins are set such so that they don't constantly sink current :)
- outa[9] := 0 'Pull the data input of the badge's hardware shift register low
- repeat Index from 0 to 7 'Clock and latch 8 of those lows into the badge's hardware shift register
- outa[8] := 1
- outa[8] := 0
- fds.Start(31, 30, 0, 115_200) 'Start up the software UART serial driver
- waitcnt((clkfreq / 2) + cnt) 'Pause for 500ms while the UART starts up
- PrintMenu 'Call the Print Menu subroutine
- Pub PrintMenu 'Spam the serial console with some useful information
- fds.Str(String("Cyphercon Badge Bug by @Whixr", 10, 13))
- fds.Str(String("--------------------------------------------------", 10, 13))
- fds.Str(String(" ~: set encryption seed", 10, 13))
- fds.Str(String(" Other: add a character to the buffer", 10, 13))
- fds.Str(String(" Backspace: remove last character from the buffer", 10, 13))
- fds.Str(String(" Enter: run encryption", 10, 13))
- fds.Str(String(" $: print current input buffer", 10, 13))
- fds.Str(String(" `: print this menu", 10, 13))
- Pub ScanConsole | Index, SubIndex, CheckByte, InputData, EncodeCheck
- 'Serial Command Console
- CheckByte := fds.RxCheck 'Put incoming byte from the serial console into CheckByte, is -1 if nothing new is waiting
- case CheckByte 'See what we got
- 8, 127: 'We got a Backspace (standards for a backspace are strange, so I included two of them: 8, 127)
- if BufferPointer > 0
- BufferPointer-- 'Move the buffer pointer back, essentially erasing what ever they entered last
- fds.Tx(8) 'Print a backspace to the console to move the cursor back, the messy wrong way :D
- 13: 'CR 'They hit Enter, so it's time to Encrypt All the Things
- PreEncrypt 'Call the PreEncrypt subroutine
- fds.Str(String(10, 13)) 'Print a CRLF to the serial console so we're starting on a new line
- repeat Index from 0 to BufferPointer - 1 'Iterate through how ever much of the buffer they filled up while typing in their super secret messages
- if BufferPointer - 1 == Index 'If this is the last character from the buffer,
- IsLast := 1 'set the flag so that we're aware of it (in case after encryption we end in a trailing Column Shift character)
- case BYTE[@Buffer][Index] 'Let's look at what kind of character we are dealing with at this position in the buffer
- "=": 'a run of 6 000s 'Looks like this character is a "=", which is an escape code for six Column Shift characters in a row
- repeat SubIndex from 0 to 5
- Clock(0) 'Send six Column Shifts down the encoder>encrypter>decoder chain
- "+": 'a hanging 000 'Looks like this character is a "+", which is an escape code for a handing Column Shift character
- Clock(0) 'Send a Column Shift down the encoder>encrypter>decoder chain
- other: 'Looks like this character is not an escape code
- EncodeCheck := 0 'Flag to know when we've found a matching letter
- repeat while EncodeCheck == 0 'Loop until the flag goes high
- repeat SubIndex from 0 to 6 'Loop through the 7 characters (rows) on the currently selected column in the CypherTTY matrix
- if BYTE[@Buffer][Index] == BYTE[@uCase][(P * 7) + SubIndex] 'Check to see if the character matches
- Clock(SubIndex + 1) 'Send the row value down the encoder>encrypter>decoder chain
- EncodeCheck := 1 'Raise the flag
- if EncodeCheck == 0 'Check if the flag was never raised
- P := P + 1 'No match in this column
- P := P // 6 'Move to the next column
- Clock(0) 'Send a Column Shift down the encoder>encrypter>decoder chain
- fds.Str(String(10, 13)) 'We're ALL DONE with the buffer so send a CRLF to the serial console for a new line
- "`": 'We got a "`" so we have to spit the help menu out to the serial console
- PrintMenu 'Call the PrintMenu subroutine
- "$": 'Print Buffer 'We got a "$" so we have to print all of the message they have entered so far back to the serial console
- fds.Str(String(10, 13)) 'Send a CRLF to the serial console
- repeat Index from 0 to BufferPointer - 1 'Loop through all of the buffer that they have filled
- fds.Tx(BYTE[@Buffer][Index]) 'Send each character to the serial console
- fds.Str(String(10, 13)) 'Send another CRLF to the serial console
- 126:'Tilde 'We got a "~" so we need to go into seed entry mode
- SeedEntry 'Call the SeedEntry subroutine
- -1: 'We didn't get anything
- 'no bytes waiting 'Sit and spin :)
- other: 'We got a character that isn't used to control the serial console
- 'This is probably something the user wants to add to the message buffer
- case InputCheck(CheckByte) 'Pass it along to the InputCheck function to see if it is a CypherTTY character
- -1: 'unsupported character 'It is not supported
- fds.Str(String(10, 13, "Character unsupported by CipherTTY ")) 'Spit out a helpful error message to the serial console
- fds.Dec(CheckByte)
- fds.Tx(32)
- fds.Tx(CheckByte)
- fds.Str(String(10, 13))
- other: 'Yes, this is a CypherTTY character
- if BufferPointer < 1023 'Check to make sure the buffer isn't full
- Buffer[BufferPointer] := InputCheck(CheckByte) 'Put the character in the buffer
- fds.Tx(Buffer[BufferPointer]) 'Print the character to the serial console
- BufferPointer++ 'Increment the buffer pointer to the next slot up in the buffer
- Pri SeedEntry | Index, SubIndex, InputData
- dirb := 0 'Zero out the dirb register
- fds.Str(String(10, 13, "Input 8 seed bits", 10, 13)) 'Let serial console user know to enter a seed
- repeat Index from 7 to 0 'Loop through all 8 bits of the seed. High bit to low bit.
- InputData := fds.Rx 'Input a character from the serial console
- case InputData 'Look at what we got
- "0": 'We got a 0
- fds.Tx(48) 'Print a 0 to the serial console
- dirb[Index] := 0 'Set this bit of seed to a 0 in the dirb register
- "1": 'We got a 1
- fds.Tx(49) 'Print a 1 to the serial console
- dirb[Index] := 1 'Set this bit of seed to a 1 in the dirb register
- other: 'We got something that isn't a 0 or a 1
- fds.Str(String(10, 13, "Binary is hard, try again ace.", 10, 13)) 'Provide life guidance to the serial console
- Index++ 'We need to enter for this bit of the seed again, so increment our loop variable (it counts down)
- repeat SubIndex from 7 to Index 'Print all of the seed that they have entered so far to the serial console
- case dirb[SubIndex]
- 0:
- fds.Tx(48)
- 1:
- fds.Tx(49)
- BackupSR_ := dirb 'Save a copy of the completed seed to the BackupSR_ global variable
- fds.Str(String(10, 13, "OK", 10, 13)) 'Send a victory message to the serial console
- Pri PreEncrypt 'Time to reset some global variables before starting the encode/encrypt/decode chain
- P := 0 'Encoder column pointer
- oP := 0 'Decoder column pointer
- FullLoop := 0 'Flag for detecting a run of six Column Shifts
- if BackupSR_ == 0 'Check to see if the user has entered a seed
- SeedEntry 'Make them enter a seed
- SR_ := BackupSR_ 'Copy the seed into the working linear feedback shift register variable
- IsLast := 0 'Flag for detecting a trailing Column Shift
- Pub Clock(Character) | Index, X0R, NextBit 'The Encrypter
- dirb := Character 'Load these three bits into the dirb register
- repeat Index from 2 to 0 'Loop through the three character bits
- outa[10 + Index] := dirb[Index] 'Set the three input indicator LEDs to match each bit
- dirb := SR_ 'Load the value of the working linear feedback shift register into the dirb register
- outa[16..18] := dirb[1..3] 'Set the three Key Bit inputs on the badge to bits 1, 2, and 3 of the LFSR
- X0R := Character ^ dirb[1..3] 'XOR the keybits with the three character bits (this is the encryption)
- Decode(X0R) 'Pass the encrypted bits down the chain to the decoder
- 'itterate to next lfsr state
- dirb := SR_ 'Load the value of the working linear feedback shift register into the dirb register
- NextBit := dirb[6] ^ dirb[7] 'Store the result of XORing the 6 and 7 bits of the LSFR (this is the feedback)
- repeat Index from 7 to 1 'Shift the contents of register dirb left by one
- dirb[Index] := dirb[Index - 1]
- dirb[0] := NextBit 'Put the stored feedback bit into bit 0 of the dirb register
- SR_ := dirb 'Store the value of the dirb register into the working linear feedback shift register
- UpdateDisplay 'Call the UpdateDisplay sub routine
- outa[8] := 1 'Turn on the STEP LED on the badge
- waitcnt((clkfreq / 10) + cnt) 'Wait 100ms
- outa[8] := 0 'Turn off the STEP LED on the badge
- waitcnt((clkfreq / 10) + cnt) 'Wait 100ms
- Pri Decode(Bits) 'The Decoder
- case Bits 'Look at what character bits we're dealing with
- 0: 'We got a Column Shift character
- case IsLast
- 0: 'Column Shift 'This Column Shift is not the final character of the message
- oP := (oP + 1) // 6 'Shift to the next column
- FullLoop++ 'Note that we've shifted again
- if FullLoop > 5 'Check if this is the 6th Column Shift in a row
- fds.Tx("=") 'Print a "=" character to the serial console
- FullLoop := 0 'Reset the Column Shift count to 0
- 1: 'This Column Shift is the final character of the message
- fds.Tx("+") 'Print a "+" character to the serial console
- other: 'We got a printable character
- FullLoop := 0 'Reset the Column Shift count to 0
- fds.Tx(BYTE[@uCase][(oP * 7) + (Bits - 1)]) 'Look up and print the printable character to the serial console
- Pub UpdateDisplay | Index 'Linear feedback shift register indicator lights
- dirb := SR_ 'Load the working linear feedback shift register into the dirb register
- outa[0..7] := dirb[0..7] 'Turn on or off the LFSR indicator lights to match the present states of the LFSR
- Pri InputCheck(InputByte) | Index, OutputByte 'If character is supported, convert to uppercase
- OutputByte := -1 'Set return to a default of unsupported
- repeat Index from 0 to 41 'Loop through the supported character table
- if InputByte == BYTE[@lCase][Index] or InputByte == BYTE[@uCase][Index] 'This InputByte was found
- OutputByte := BYTE[@uCase][Index] 'Set return to the uppercase version of this character
- if InputByte == "+" 'This InputByte is a hanging Column Shift escape code
- OutputByte := "+" 'Pass this character along
- if InputByte == "=" 'This InputByte is a Run of Six Column Shifts escape code
- OutputByte := "=" 'Pass this character along
- return OutputByte 'Return the result
- Dat 'CypherTTY supported character table
- lCase byte " et.0123456789,?!", 34, "aoinshrdlcumwfgypbvkjxqz"
- uCase byte " ET.0123456789,?!", 34, "AOINSHRDLCUMWFGYPBVKJXQZ"
- {{
- ┌──────────────────────────────────────────────────────────────────────────────────────┐
- │ TERMS OF USE: MIT License │
- ├──────────────────────────────────────────────────────────────────────────────────────┤
- │Permission is hereby granted, free of charge, to any person obtaining a copy of this │
- │software and associated documentation files (the "Software"), to deal in the Software │
- │without restriction, including without limitation the rights to use, copy, modify, │
- │merge, publish, distribute, sublicense, and/or sell copies of the Software, and to │
- │permit persons to whom the Software is furnished to do so, subject to the following │
- │conditions: │
- │ │
- │The above copyright notice and this permission notice shall be included in all copies │
- │or substantial portions of the Software. │
- │ │
- │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, │
- │INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A │
- │PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT │
- │HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION │
- │OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
- │SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
- └──────────────────────────────────────────────────────────────────────────────────────┘
- }}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement