So, I've decided to share my Proton BASIC implementation of the U.S. NSA's Skipjack Encryption algorithm.
Skipjack is a secure block cipher, it utilizes an 80-bit keyspace, and works on 64-bit blocks of data. It is a 32 round unbalanced Feistel network.
Background Info @ Wikipedia, Full Specifications, Cryptanalysis.
Cryptanalysis has shown that the best attacks on the algorithm fair no better than brute force, making this algorithm more secure than DES.
My particular implementation was focused on reducing the code footprint due to its intended use in a bootloader, code space is precious.
Also, the code has been optimized in such a way so it compiles as small as possible, this makes the code more difficult to read, but by no means is it unmanageable.
It makes use of quite a lot of RAM and is suited for 18F devices. I reasoned that I could afford to consume the RAM during bootloader operation, as it would be invalidated once the application code started running.
Currently the compile stats are as follows using the latest compiler (Beta as of this writing 3.5.1.5):
RAM Required: 2,861 bytes
Code Size: (Encrypt AND Decrypt) 1,242 bytes
Code Size: (Encrypt OR Decrypt) 842 bytes
This doesn't include assigning the key, data, or any of the demo related code, only the algorithm with 256 byte F Table.
Check the source code header or the full specification for test vectors.
I'm releasing this under the MIT License, feel free to do with it what you will.
If you use this in a commercial project and/or find it really useful, karma dictates you buy me a beer.
Code:
'****************************************************************
'* Name : SKIPJACK_TINYCODE.BAS [SKIPJACKtc] *
'* Author : Phil Ciebiera *
'* Notice : Copyright ©2011 Phil Ciebiera *
'* Date : 2/22/2011 *
'* Revised : 3/12/2011 *
'* Version : 2.2.137 *
'******************************INFO******************************
'* Implements the Skipjack algorithm present in the *
'* Clipper chip developed by the U.S. NSA. *
'* Read More: *
'* Wikipedia [http://bit.ly/13sHSf] *
'* Full Spec @ nist.gov [http://1.usa.gov/fcuUR9] *
'* Cryptanalysis of Skipjack [http://bit.ly/ezLfUi] *
'* *
'* This version is optimized to reduce the code footprint as *
'* much as possible. The tradeoff being RAM usage is increased. *
'* Ideal for use in secure Bootloaders. *
'* *
'* RAM Required: 2,861 bytes *
'* Code Size: (Encrypt AND Decrypt) 1,242 bytes *
'* Code Size: (Encrypt OR Decrypt) 842 bytes *
'* *
'* Test Vector: *
'* Key: 0x00998877665544332211 *
'* Plain Text: 0x33221100DDCCBBAA *
'* Cipher Text: 0x2587CAE27A12D300 *
'************************MIT**LICENSE****************************
'* Copyright (C) 2011 by Phil Ciebiera *
'* *
'* 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. *
'* *
'* Except as contained in this notice, the name(s) of the above *
'* copyright holders shall not be used in advertising or *
'* otherwise to promote the sale, use or other dealings in this *
'* Software without prior written authorization. *
'* *
'* 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. *
'****************************************************************
' --- BEGIN: DEVICE CONFIG RELATED ---
Declare Optimiser_Level = 3
Device 18F46K22
Xtal 16
All_Digital True
Config_Start
FOSC = INTIO67 ' Internal oscillator block, port function on RA6 and RA7
PLLCFG = On ' Oscillator multiplied by 4
PRICLKEN = On ' Primary clock is always enabled
FCMEN = Off ' Fail-Safe Clock Monitor disabled
IESO = Off ' Oscillator Switchover mode disabled
PWRTEN = Off ' Power up timer disabled
BOREN = Off ' Brown-out Reset disabled in hardware and software
WDTEN = Off ' Watch dog timer is always disabled. SWDTEN has no effect.
WDTPS = 1 ' 1:1
CCP2MX = PORTB3 ' CCP2 input/output is multiplexed with RB3
PBADEN = Off ' PORTB<5:0> pins are configured as digital I/O on Reset
CCP3MX = PORTB5 ' P3A/CCP3 input/output is multiplexed with RB5
HFOFST = On ' HFINTOSC output and ready status are not delayed by the oscillator stable status
T3CMX = PORTC0 ' T3CKI is on RC0
P2BMX = PORTD2 ' P2B is on RD2
MCLRE = EXTMCLR ' MCLR pin enabled, RE3 input pin disabled
STVREN = Off ' Stack full/underflow will not cause Reset
LVP = On ' Single-Supply ICSP enabled if MCLRE is also 1
XINST = Off ' Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
Debug = Off ' Disabled
CP0 = Off ' Block 0 (000800-003FFFh) not code-protected
CP1 = Off ' Block 1 (004000-007FFFh) not code-protected
CP2 = Off ' Block 2 (008000-00BFFFh) not code-protected
CP3 = Off ' Block 3 (00C000-00FFFFh) not code-protected
CPB = Off ' Boot block (000000-0007FFh) not code-protected
CPD = Off ' Data EEPROM not code-protected
WRT0 = Off ' Block 0 (000800-003FFFh) not write-protected
WRT1 = Off ' Block 1 (004000-007FFFh) not write-protected
WRT2 = Off ' Block 2 (008000-00BFFFh) not write-protected
WRT3 = Off ' Block 3 (00C000-00FFFFh) not write-protected
WRTC = Off ' Configuration registers (300000-3000FFh) not write-protected
WRTB = Off ' Boot Block (000000-0007FFh) not write-protected
WRTD = Off ' Data EEPROM not write-protected
EBTR0 = Off ' Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
EBTR1 = Off ' Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
EBTR2 = Off ' Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
EBTR3 = Off ' Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
EBTRB = Off ' Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End
' Configure oscillator
OSCCON.4 = 1 '
OSCCON.5 = 1 ' 16MHZ
OSCCON.6 = 1 '
' --- END: DEVICE CONFIG RELATED ---
' --- BEGIN: SKIPJACK RELATED ---
' Used for RAM access
Dim FSRPointer0 As FSR0L.Word
Dim FSRPointer1 As FSR1L.Word
' Various temporary working variables
Dim SJ_wSub1 As Word
Dim SJ_wSub2 As Word
Dim SJ_bSub1 As Byte
Dim SJ_bSub2 As Byte
Dim SJ_bSub3 As Byte
Dim SJ_bSub4 As Byte
Dim SJ_bSub5 As Byte
Dim SJ_bRound As Byte
Dim SJ_bSteppingRule As Byte
Dim SJ_bG_KeyTableOrder[5] As Byte
Dim SJ_bCurrentVariation As Byte
Dim SJ_bCurrentWorkItem As Byte
Dim SJ_bCurrentManipulationItem As Byte
' This holds the block for encryption/decryption
Dim SJ_WORK[4] As Word
' This holds our 80-bit key
Dim SJ_KEY[10] As Byte
' These are working tables that are built from the chosen key.
' It's very memory hungry, but this is optimized to reduce the code footprint
Dim tab[256] As Byte
Dim tab0[256] As Byte
Dim tab1[256] As Byte
Dim tab2[256] As Byte
Dim tab3[256] As Byte
Dim tab4[256] As Byte
Dim tab5[256] As Byte
Dim tab6[256] As Byte
Dim tab7[256] As Byte
Dim tab8[256] As Byte
Dim tab9[256] As Byte
' --- PAUSE: SKIPJACK RELATED ---
' --- BEGIN: DEMO RELATED ---
' Calculated Baudrate = 9592 @ Xtal 16MHz, Error = -0.08%
RCSTA = 144 ' Enable continuous receive
TXSTA = 36 ' Enable transmit, BRGH = 1
SPBRG = 160 ' Baud Rate Generator Low Byte Value
SPBRGH = 1 ' Baud Rate Generator High Byte Value
BAUDCTL.3 = 1 ' Enable the 16 bit Baud Rate Generator
' Assign our Key
SJ_KEY[0] = $00
SJ_KEY[1] = $99
SJ_KEY[2] = $88
SJ_KEY[3] = $77
SJ_KEY[4] = $66
SJ_KEY[5] = $55
SJ_KEY[6] = $44
SJ_KEY[7] = $33
SJ_KEY[8] = $22
SJ_KEY[9] = $11
' Assign our plaintext for encryption
SJ_WORK[0] = $3322
SJ_WORK[1] = $1100
SJ_WORK[2] = $DDCC
SJ_WORK[3] = $BBAA
' Wait for a bit
DelayMS 3000
HSerOut ["Generating Key Tables [",Hex2 SJ_KEY[0],Hex2 SJ_KEY[1],Hex2 SJ_KEY[2],Hex2 SJ_KEY[3],Hex2 SJ_KEY[4],Hex2 SJ_KEY[5],Hex2 SJ_KEY[6],Hex2 SJ_KEY[7],Hex2 SJ_KEY[8],Hex2 SJ_KEY[9],"]..."]
' Generate key tables, you only need to do this once, before encrypting or decrypting
GoSub SJ_MakeKeyTables
HSerOut ["Done!",13,10,"Encrypting ",Hex4 SJ_WORK[0],Hex4 SJ_WORK[1],Hex4 SJ_WORK[2],Hex4 SJ_WORK[3],"..."]
' Call the encryption function to work on the data in SJ_WORK[0-3] using the key in SJ_KEY[0-9]
GoSub SJ_Encrypt
HSerOut ["Done!",13,10,"Encrypted Data: ",Hex4 SJ_WORK[0],Hex4 SJ_WORK[1],Hex4 SJ_WORK[2],Hex4 SJ_WORK[3],13,10,"Decrypting ",Hex4 SJ_WORK[0],Hex4 SJ_WORK[1],Hex4 SJ_WORK[2],Hex4 SJ_WORK[3],"..."]
' Call the decryption function to work on the data in SJ_WORK[0-3] using the key in SJ_KEY[0-9]
GoSub SJ_Decrypt
HSerOut ["Done!",13,10,"Decrypted Data: ",Hex4 SJ_WORK[0],Hex4 SJ_WORK[1],Hex4 SJ_WORK[2],Hex4 SJ_WORK[3],13,10,13,10,"STOP"]
Stop
' --- END: DEMO RELATED ---
' --- RESUME: SKIPJACK RELATED ---
' Generates the precomputed key tables in RAM, this is done in RAM to minimize the code footprint
SJ_MakeKeyTables:
SJ_bSub1 = 0
SJ_wSub1 = VarPtr tab0
Repeat
SJ_bSub2 = SJ_KEY[SJ_bSub1]
SJ_bSub3 = 0
Repeat
SJ_bSub4 = SJ_bSub3 ^ SJ_bSub2
SJ_bSub5 = CRead FTable + SJ_bSub4
FSRPointer0 = SJ_wSub1
POSTINC0 = SJ_bSub5
Inc SJ_wSub1
Inc SJ_bSub3
Until SJ_bSub3 = 0
Inc SJ_bSub1
Until SJ_bSub1 = 10
Return
' Copies one of the key tables to the working table
CopyKeyTable:
FSRPointer1 = VarPtr tab
SJ_wSub1 = VarPtr tab0
SJ_wSub1 = SJ_wSub1 + (256 * SJ_bSub3)
FSRPointer0 = SJ_wSub1
SJ_wSub1 = 0
Repeat
POSTINC1 = POSTINC0
Inc SJ_wSub1
Until SJ_wSub1 = 256
Return
' Encrypts the data at SJ_WORK[0-3] with the key at SJ_KEY[0-9]
SJ_Encrypt:
' Intialize the temporary working variables into their proper state
SJ_bRound = 1
SJ_bG_KeyTableOrder[0] = 0
SJ_bG_KeyTableOrder[1] = 4
SJ_bG_KeyTableOrder[2] = 8
SJ_bG_KeyTableOrder[3] = 2
SJ_bG_KeyTableOrder[4] = 6
SJ_bCurrentVariation = 0
SJ_bCurrentWorkItem = 0
SJ_bSteppingRule = 1
SJ_bCurrentManipulationItem = 3
Repeat
If SJ_bSteppingRule = 2 Then SJ_WORK[SJ_bCurrentManipulationItem] = SJ_WORK[SJ_bCurrentManipulationItem] ^ (SJ_WORK[SJ_bCurrentWorkItem] ^ SJ_bRound) ' Stepping B Manipulations
SJ_bSub3 = SJ_bG_KeyTableOrder[SJ_bCurrentVariation] ' Assign the correct starting key table for our G function
SJ_wSub2 = SJ_WORK[SJ_bCurrentWorkItem] ' Assign the holding register into the worker variable
' Run the G Permutation
SJ_bSub1 = 0
G_Top:
Inc SJ_bSub1
GoSub CopyKeyTable
SJ_wSub2 = SJ_wSub2 ^ (tab[SJ_wSub2.LowByte] << 8)
Inc SJ_bSub3
GoSub CopyKeyTable
SJ_wSub2 = SJ_wSub2 ^ (tab[SJ_wSub2.HighByte])
Inc SJ_bSub3
If SJ_bSub3 = 10 Then SJ_bSub3 = 0
If SJ_bSub1 <> 2 Then GoTo G_Top
SJ_WORK[SJ_bCurrentWorkItem] = SJ_wSub2 ' Assign the worked variable back into the holding register
If SJ_bSteppingRule = 1 Then SJ_WORK[SJ_bCurrentManipulationItem] = SJ_WORK[SJ_bCurrentManipulationItem] ^ (SJ_WORK[SJ_bCurrentWorkItem] ^ SJ_bRound) ' Stepping A Manipulations
' Increments the various work counters
Inc SJ_bCurrentVariation ' Increment the G variation on each round
If SJ_bCurrentVariation = 5 Then SJ_bCurrentVariation = 0 ' Ensure that we start over at G0 after completing G4
If SJ_bCurrentManipulationItem = 0 Then SJ_bCurrentManipulationItem = 4 ' Ensure that we don't overflow the manipulation item counter
Dec SJ_bCurrentManipulationItem ' Decrement the manipulation item counter
If SJ_bCurrentWorkItem = 0 Then SJ_bCurrentWorkItem = 4 ' Ensure that we don't overflow the G function input counter
Dec SJ_bCurrentWorkItem ' Decrement the G function input counter
If SJ_bRound // 8 = 0 Then ' Change the stepping rule every 8 rounds
If SJ_bSteppingRule = 1 Then ' Currently, we're Rule A stepping
SJ_bSteppingRule = 2 ' Switch to Rule B stepping
SJ_bCurrentManipulationItem = 1 ' Reset the manipulation item counter for the next set of rounds
Else ' Otherwise, we're currently Rule B stepping
SJ_bSteppingRule = 1 ' Switch to Rule A stepping
SJ_bCurrentManipulationItem = 3 ' Reset the manipulation item counter for the next set of rounds
EndIf
EndIf
Inc SJ_bRound ' Increment the round counter
Until SJ_bRound = 33 ' Loop until we've completed 32 rounds
Return
' Decrypts the data at SJ_WORK[0-3] with the key at SJ_KEY[0-9]
SJ_Decrypt:
' Intialize the temporary working variables into their proper state
SJ_bRound = 32
SJ_bG_KeyTableOrder[0] = 3
SJ_bG_KeyTableOrder[1] = 7
SJ_bG_KeyTableOrder[2] = 1
SJ_bG_KeyTableOrder[3] = 5
SJ_bG_KeyTableOrder[4] = 9
SJ_bCurrentVariation = 1
SJ_bCurrentWorkItem = 1
SJ_bSteppingRule = 1
SJ_bCurrentManipulationItem = 2
Repeat
If SJ_bSteppingRule = 2 Then SJ_WORK[SJ_bCurrentManipulationItem] = SJ_WORK[SJ_bCurrentManipulationItem] ^ (SJ_WORK[SJ_bCurrentWorkItem] ^ SJ_bRound) ' Stepping B Manipulations
SJ_bSub3 = SJ_bG_KeyTableOrder[SJ_bCurrentVariation] ' Assign the correct starting key table for our H function
SJ_wSub2 = SJ_WORK[SJ_bCurrentWorkItem] ' Assign the holding register into the worker variable
' Run the H permutation
SJ_bSub1 = 0
H_Top:
Inc SJ_bSub1
GoSub CopyKeyTable
SJ_wSub2 = SJ_wSub2 ^ (tab[SJ_wSub2.HighByte])
Dec SJ_bSub3
GoSub CopyKeyTable
SJ_wSub2 = SJ_wSub2 ^ (tab[SJ_wSub2.LowByte] << 8)
If SJ_bSub3 = 0 Then SJ_bSub3 = 10
Dec SJ_bSub3
If SJ_bSub1 <> 2 Then GoTo H_Top
SJ_WORK[SJ_bCurrentWorkItem] = SJ_wSub2 ' Assign the worked variable back into the holding register
If SJ_bSteppingRule = 1 Then SJ_WORK[SJ_bCurrentManipulationItem] = SJ_WORK[SJ_bCurrentManipulationItem] ^ (SJ_WORK[SJ_bCurrentWorkItem] ^ SJ_bRound) ' Stepping A Manipulations
If SJ_bCurrentVariation = 0 Then SJ_bCurrentVariation = 5 ' Ensure that we start over at H4 after completing H0
Dec SJ_bCurrentVariation ' Decrement the H variation on each round
Inc SJ_bCurrentManipulationItem ' Increment the manipulation item counter
If SJ_bCurrentManipulationItem = 4 Then SJ_bCurrentManipulationItem = 0 ' Ensure that we don't overflow the manipulation item counter
Inc SJ_bCurrentWorkItem ' Increment the H function Input Counter
If SJ_bCurrentWorkItem = 4 Then SJ_bCurrentWorkItem = 0 ' Ensure that we don't overflow the H function input counter
Dec SJ_bRound ' Decrement the round counter
If SJ_bRound // 8 = 0 Then ' Change the stepping rule every 8 rounds
If SJ_bSteppingRule = 1 Then ' Currently, we're Rule A stepping
SJ_bSteppingRule = 2 ' Switch to Rule B stepping
SJ_bCurrentManipulationItem = 0 ' Reset the manipulation item counter for the next set of rounds
Else ' Otherwise, we're currently Rule B stepping
SJ_bSteppingRule = 1 ' Switch to Rule A stepping
SJ_bCurrentManipulationItem = 2 ' Reset the manipulation item counter for the next set of rounds
EndIf
EndIf
Until SJ_bRound = 0 ' Loop until we've completed 32 rounds in reverse order
Return
' F Table, this is specified by the Skipjack algorithm
FTable:
CData $A3, $D7, $09, $83, $F8, $48, $F6, $F4, $B3, $21, $15, $78, $99, $B1, $AF, $F9
CData $E7, $2D, $4D, $8A, $CE, $4C, $CA, $2E, $52, $95, $D9, $1E, $4E, $38, $44, $28
CData $0A, $DF, $02, $A0, $17, $F1, $60, $68, $12, $B7, $7A, $C3, $E9, $FA, $3D, $53
CData $96, $84, $6B, $BA, $F2, $63, $9A, $19, $7C, $AE, $E5, $F5, $F7, $16, $6A, $A2
CData $39, $B6, $7B, $0F, $C1, $93, $81, $1B, $EE, $B4, $1A, $EA, $D0, $91, $2F, $B8
CData $55, $B9, $DA, $85, $3F, $41, $BF, $E0, $5A, $58, $80, $5F, $66, $0B, $D8, $90
CData $35, $D5, $C0, $A7, $33, $06, $65, $69, $45, $00, $94, $56, $6D, $98, $9B, $76
CData $97, $FC, $B2, $C2, $B0, $FE, $DB, $20, $E1, $EB, $D6, $E4, $DD, $47, $4A, $1D
CData $42, $ED, $9E, $6E, $49, $3C, $CD, $43, $27, $D2, $07, $D4, $DE, $C7, $67, $18
CData $89, $CB, $30, $1F, $8D, $C6, $8F, $AA, $C8, $74, $DC, $C9, $5D, $5C, $31, $A4
CData $70, $88, $61, $2C, $9F, $0D, $2B, $87, $50, $82, $54, $64, $26, $7D, $03, $40
CData $34, $4B, $1C, $73, $D1, $C4, $FD, $3B, $CC, $FB, $7F, $AB, $E6, $3E, $5B, $A5
CData $AD, $04, $23, $9C, $14, $51, $22, $F0, $29, $79, $71, $7E, $FF, $8C, $0E, $E2
CData $0C, $EF, $BC, $72, $75, $6F, $37, $A1, $EC, $D3, $8E, $62, $8B, $86, $10, $E8
CData $08, $77, $11, $BE, $92, $4F, $24, $C5, $32, $36, $9D, $CF, $F3, $A6, $BB, $AC
CData $5E, $6C, $A9, $13, $57, $25, $B5, $E3, $BD, $A8, $3A, $01, $05, $59, $2A, $46
' --- END: SKIPJACK RELATED ---


Menu
Recent Articles


Using PDS with SPI GLCD based on ST7565R Controller
Graphic LCDs based on the ST7565 are cheaper then GLCDs with other controllers. SPI requires only four pins. If the circuit