DES/3DES Cipher Module

Share your advanced PureBasic knowledge/code with the community.
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

DES/3DES Cipher Module

Post by coco2 »

Hey all I thought I would post up my first PB release, and I thought I'd start simple with a little TripleDES module. Run it by itself to see a self test. Feel free to make suggestions, I'm only new to PB so hopefully I can get a bit better with future releases.

Release history:
1.0 - 2014-Jun-02 - initial release
1.0.1 - 2014-Jun-03 - minor fix (incorrect key size for 168 bit 3DES)
1.0.2 - 2014-Jun-04 - bug fix in test and added some more global procedures. Input size in multiples of 8 is now enforced and a result of 0 is returned if not

Code: Select all

; ==========================================================================
; DES/3DES cipher module (native PureBasic x86)
; Module version: 1.0.2 (non-optimised)
; Description:
; Cipher: DES/TripleDES EDE CBC
; Key options: 56, 112 and 168 bit (DES is 56 bit only)
; Block mode: CBC
; Optimisiations:
; - global key schedule
; OS: all (Win/Lin/Mac)
; Developed on: PB 5.22 LTS x64 / Windows 7 x64
; Author: coco2
; Credit: see "further reading" list below
; Created:  30-May-2014
; Modified: 03-Jun-2014
; License: open
; Release history:
;   1.0   - 2014-Jun-02 - initial release
;   1.0.1 - 2014-Jun-03 - minor fix (incorrect key size for 168 bit 3DES)
;   1.0.2 - 2014-Jun-04 - bug fix in test and added some more global
;                         procedures. Input size in multiples of 8 is now
;                         enforced and a result of 0 is returned if not
;
; Provided "as is" with no warranty and no liability.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.
;
; Notes:
; 1. The authors/copyright holder(s) of this module are not affiliated with
;    the PureBasic software authors/copyright holders.
; 2. This DES/3DES module is intended for educational purposes or for
;    legacy applications and not encrypting sensitive data since:
;    2.1. DES is considered outdated and too weak for securing data.
;    2.2. 3DES is still in use but is not recommended due to meet-in-the-middle
;         attacks.
; ==========================================================================
; 
; Further reading:
; 
; - http://en.wikipedia.org/wiki/Data_Encryption_Standard
; - http://en.wikipedia.org/wiki/Triple_DES
; - Implementing SSL / TLS Using Cryptography and PKI
;   (ISBN: 978-0-470-92041-1)
; - FIPS PUB 46-3 (http://csrc.nist.gov/publications/fips/fips46-3/
;   fips46-3.pdf)
; - Helpful site: http://dhost.info/pasjagor/des/start.php?id=0
;
; ==========================================================================

PurifierGranularity(1,1,1,1)

EnableExplicit

DeclareModule DES
  
  ;- Public constants
  
  Enumeration DES_Operation
    #DES_ENCRYPT
    #DES_DECRYPT
  EndEnumeration 
  
  #DES_BLOCK_SIZE = 8
  #DES_KEY_SIZE = 8
  
  ;- Public procedures
  
  Declare MakeIV(*IV)
  Declare DESEncryptCBC(*in, length.i, *out, *iv, *key)  
  Declare DESDecryptCBC(*in, length.i, *out, *iv, *key)      
  Declare TripleDESEncryptCBC(*in, length.i, *out, *iv, *key, key_length.i)
  Declare TripleDESDecryptCBC(*in, length.i, *out, *iv, *key, key_length.i)
  Declare TripleDES112EncryptCBC(*in, length.i, *out, *iv, *key)
  Declare TripleDES112DecryptCBC(*in, length.i, *out, *iv, *key)
  Declare TripleDES168EncryptCBC(*in, length.i, *out, *iv, *key)
  Declare TripleDES168DecryptCBC(*in, length.i, *out, *iv, *key)  
  
EndDeclareModule

Module DES
  
  ;- Private constants
  
  #DES_EXPANSION_BLOCK_SIZE = 6
  #DES_PC1_KEY_SIZE = 7
  #DES_SUBKEY_SIZE = 6  
  
  ;- Private globals
  
  ; DES lookup tables
  Global Dim IP_Table.a(63)
  Global Dim FP_Table.a(63)
  Global Dim PC1_Table.a(55)
  Global Dim PC2_Table.a(55)
  Global Dim Expansion_Table.a(47)
  Global Dim sbox.a(7, 63)
  Global Dim P_Table.a(31)
  Global Dim Precomputed_subkeys.a(7, 15, 2) ; key bytes (0-7), round (0-15), key set (0-2)
  
  ; scratch arrays
  Global Dim IP_Block.a(#DES_BLOCK_SIZE-1)
  Global Dim IP_Block_Low.a(#DES_BLOCK_SIZE/2 - 1)
  Global Dim Expansion_Block.a(#DES_EXPANSION_BLOCK_SIZE-1)
  Global Dim Substitution_Block.a(#DES_BLOCK_SIZE / 2 - 1)
  Global Dim pbox_target.a(#DES_BLOCK_SIZE / 2 - 1)
  Global Dim recomb_box.a(#DES_BLOCK_SIZE / 2 - 1)
  Global Dim pc1key.a(#DES_PC1_KEY_SIZE-1)
  Global Dim subkey.a(#DES_SUBKEY_SIZE-1)
  
  ; Private procedures
  
  Procedure XORMem(*Target, *Source, length.i)
    ; XORs target With source array And places result in target array
    Define.i c ; counter
    Define.a sv, tv ; source and target value
    For c=0 To length-1
      tv=PeekA(*Target+c)
      sv=PeekA(*Source+c)
      tv = tv ! sv
      PokeA(*Target+c,tv)
    Next
  EndProcedure
  
  Procedure Permute(Array Target.a(1), Array Source.a(1), Array permuteTable.a(1), length.i)
    Define.a i=0, bit
    While i<length*8
      bit=permuteTable(i)-1
      If Source(bit/8)&(128>>(bit%8)) ; get the state of the bit
        Target(i/8)|(128>>(i%8)) ; set the bit
      Else
        Target(i/8)&~(128>>(i%8)) ; clear the bit
      EndIf
      i=i+1
    Wend
  EndProcedure
  
  Procedure RotateKeyLeft(Array Target.a(1))
    Define carry_left.a, carry_right.a
    carry_left = (Target(0) & $80) >> 3
    Target(0) = (Target(0) << 1) | ((Target(1) & $80) >> 7)
    Target(1) = (Target(1) << 1) | ((Target(2) & $80) >> 7)  
    Target(2) = (Target(2) << 1) | ((Target(3) & $80) >> 7)
    carry_right = (Target(3) & $08) >> 3
    Target(3) = (((Target(3) << 1) | ((Target(4) & $80) >> 7)) & ~$10) | carry_left
    Target(4) = (Target(4) << 1) | ((Target(5) & $80) >> 7)  
    Target(5) = (Target(5) << 1) | ((Target(6) & $80) >> 7)  
    Target(6) = (Target(6) << 1) | carry_right
  EndProcedure
  
  Procedure RotateKeyRight(Array Target.a(1))
    Define carry_left.a, carry_right.a
    carry_right = (Target(6) & $01) << 3
    Target(6) = (Target(6) >> 1) | ((Target(5) & $01) << 7)
    Target(5) = (Target(5) >> 1) | ((Target(4) & $01) << 7)  
    Target(4) = (Target(4) >> 1) | ((Target(3) & $01) << 7)
    carry_left = (Target(3) & $10) << 3
    Target(3) = (((Target(3) >> 1) | ((Target(2) & $01) << 7)) & ~$08) | carry_right
    Target(2) = (Target(2) >> 1) | ((Target(1) & $01) << 7)  
    Target(1) = (Target(1) >> 1) | ((Target(0) & $01) << 7)  
    Target(0) = (Target(0) >> 1) | carry_left
  EndProcedure
  
  Procedure.i Initialise()
    ; Called automatically
    CopyMemory(?DES_IP_Table,@IP_Table(), 64) ; initial permutation
    CopyMemory(?DES_FP_Table,@FP_Table(), 64) ; final permutation
    CopyMemory(?DES_PC1_Table,@PC1_Table(), 56) ; key permutation table 1
    CopyMemory(?DES_PC2_Table,@PC2_Table(), 56) ; key permutation table 2
    CopyMemory(?DES_Expansion_Table,@Expansion_Table(), 48) ; key expansion table
    CopyMemory(?DES_sbox1,@sbox(), 512) ; sboxes - lookup tables for scrambling the data
    CopyMemory(?DES_p_table,@P_Table(),32) ; final permute of the substitution table built from sboxes
  EndProcedure
  
  Procedure MakeIV(*IV)
    ; Generates 8 random bytes in memory located at *IV
    OpenCryptRandom()
    CryptRandomData(*IV,8)
    CloseCryptRandom() 
  EndProcedure
  
  Procedure ClearSubkeys()
    FillMemory(@Precomputed_subkeys(), 168, 0)
  EndProcedure
  
  Procedure MakeSubkeys(*key, length.i, Operation.i=#DES_ENCRYPT)
    ; Pass a pointer to 8-24 bytes to precompute subkeys in global array Precomputed_subkeys()
    ; For DES use 8 byte key, for TripleDES 8-24 bytes
    ; Note: 8 byte key produces the same output for DES and 3DES
    ; 16 and 24 byte keys only used in 3DES, DES ignores bytes >16
    Define R.i, Num_keys.i = 0, Result.i = 0
    Define Keyset.i = 0
    Define Offset.i = 0 ; the offset in the subkey array to write the next computed subkey to
    Dim temp_key.a(7)
    If Not (length % 8) Or (length = 8) ; make sure key is valid length
      Num_keys = length / 8 - 1
      For Keyset = 0 To Num_keys
        CopyMemory(*key+Keyset*#DES_KEY_SIZE, @temp_key(),8)
        Permute(pc1key(), temp_key(), PC1_table(), #DES_PC1_KEY_SIZE); generate initial subkey value
        For R = 0 To 15
          If Operation=#DES_ENCRYPT
            RotateKeyLeft(pc1key())
            If Not (R<=1 Or R=8 Or R=15)
              RotateKeyLeft(pc1key())
            EndIf
          EndIf
          Permute(subkey(), pc1key(), pc2_table(), #DES_SUBKEY_SIZE)
          If Operation=#DES_DECRYPT
            RotateKeyRight(pc1key())
            If Not (R=0 Or R=7 Or R>=14)
              RotateKeyRight(pc1key())
            EndIf        
          EndIf
          CopyMemory(@subkey(), @Precomputed_subkeys() + Offset, #DES_SUBKEY_SIZE) ; store rotated key
          Offset+#DES_SUBKEY_SIZE ; move to next subkey slot
        Next R
        Operation = 1 - Operation
      Next Keyset
      Result = 1
      If Num_keys < 2 ; Keying option 2 - K3=K1
        MoveMemory(@Precomputed_subkeys(), @Precomputed_subkeys()+192, 96)
      EndIf
      If Num_keys=0 ; Keying option 3 - K1=K2=K3 (not recommended but included for backwards compatibility)
        MoveMemory(@Precomputed_subkeys(), @Precomputed_subkeys()+96, 96)
      EndIf
    Else
      Debug "DES::MakeSubkeys: ERROR! Key length not a multiple of 8"
      Result = 0
    EndIf
    ProcedureReturn
  EndProcedure
  
  Procedure ProcessBlock(Array input_buffer.a(1), Array output_buffer.a(1), keyset.i=0)
    ; Encrypts or decrypts a 64-bit (8 byte) block of data in DES ECB mode.
    ; Pre-requisites: MUST have previously called MakeSubkeys() before using.
    ; Parameters:
    ;   input_buffer(): 64-bit (8 byte) array of input data
    ;   output_buffer(): 64-bit (8 byte) array of output data
    ;   keyset: 0, 1 or 2 to select the 3DES keyset (always 0 for DES)
    Define R.i, key_offset.i
    key_offset = keyset * 96
    Permute(ip_block(), input_buffer(), ip_table(), #DES_BLOCK_SIZE);
    For R = 0 To 15
      CopyMemory(@IP_Block()+4, @IP_Block_Low(), 4)
      Permute(expansion_block(), IP_Block_Low(), expansion_table(), 6)
      XORMem(@expansion_block(), @Precomputed_subkeys() + key_offset + (R * #DES_SUBKEY_SIZE), 6)
      FillMemory(@Substitution_Block(), 4, 0)
      substitution_block(0) = sbox(0,(expansion_block(0) & $FC) >> 2 ) << 4
      substitution_block(0) | sbox(1,(expansion_block(0) & $03) << 4 | (Expansion_Block(1) & $F0) >> 4)
      substitution_block(1) = sbox(2,(expansion_block(1) & $0F) << 2 | (Expansion_Block(2) & $C0) >> 6 ) << 4
      substitution_block(1) | sbox(3,(expansion_block(2) & $3F))
      substitution_block(2) = sbox(4,(expansion_block(3) & $FC) >> 2) << 4
      substitution_block(2) | sbox(5,(expansion_block(3) & $03) << 4 | (Expansion_Block(4) & $F0) >> 4)
      substitution_block(3) = sbox(6,(expansion_block(4) & $0F) << 2 | (Expansion_Block(5) & $C0) >> 6 ) << 4
      substitution_block(3) | sbox(7,(expansion_block(5) & $3F))
      Permute(pbox_target(), substitution_block(), P_Table(), 4)
      CopyMemory(@IP_Block(), @recomb_box(), 4)
      CopyMemory(@IP_Block()+4, @IP_Block(), 4)
      XORMem(@recomb_box(), @pbox_target(), 4)
      CopyMemory(@recomb_box(), @IP_Block()+4, 4)
    Next R    
    CopyMemory(@IP_Block(), @recomb_box(), 4)
    CopyMemory(@IP_Block()+4, @IP_Block(), 4)
    CopyMemory(@recomb_box(), @IP_Block()+4, 4)
    Permute(output_buffer(), ip_block(), fp_table(), 8) ; return processed block
  EndProcedure
  
  Procedure.i ProcessBufferCBC(*in, length.i, *out, *iv, operation.i=#DES_ENCRYPT, triple.i=#False)
    ; Encrypts or decrypts any block of data in CBC mode.
    ; Pre-requisites: MUST have previously called MakeSubkeys() before using.    
    ; Parameters:
    ; *in: pointer to input data
    ; length: size in bytes of input data (MUST be in multiples of 8)
    ; *out: output buffer (MUST be the same length as input buffer)
    ; *iv: 8 byte initialisation vector
    ; operation: #DES_DECRYPT or #DES_ENCRYPT
    ; triple: #False for DES, #True for 3DES
    ; Note: padding must be dealt with before calling
    ;
    Define result.i=0
    If Not length%8
      Dim input_block.a(#DES_BLOCK_SIZE-1)
      Dim temp_out.a(#DES_BLOCK_SIZE-1)
      Dim temp_iv.a(#DES_KEY_SIZE-1)
      Define c.i=0
      CopyMemory(*iv, @temp_iv(), #DES_KEY_SIZE)
      While c<length
        CopyMemory(*in+c, @input_block(), #DES_BLOCK_SIZE)
        If Operation=#DES_ENCRYPT
          XORMem(@input_block(), @temp_iv(), #DES_BLOCK_SIZE)
          ProcessBlock(input_block(), temp_out(), 0) ; DES and 3DES encrypt
          If triple ; 3DES encrypt
            CopyMemory(@temp_out(), @input_block(), #DES_BLOCK_SIZE)
            ProcessBlock(input_block(), temp_out(), 1)
            CopyMemory(@temp_out(), @input_block(), #DES_BLOCK_SIZE)
            ProcessBlock(input_block(), temp_out(), 2)
          EndIf
          CopyMemory(@temp_out(), @temp_iv(), #DES_BLOCK_SIZE) ; update IV
        Else ; Decrypt
          If triple ; 3DES decrypt
            ProcessBlock(input_block(), temp_out(), 2)
            CopyMemory(@temp_out(), @input_block(), #DES_BLOCK_SIZE)
            ProcessBlock(input_block(), temp_out(), 1)
            CopyMemory(@temp_out(), @input_block(), #DES_BLOCK_SIZE)
          EndIf
          ProcessBlock(input_block(), temp_out(), 0)
          XORMem(@temp_out(), @temp_iv(), #DES_BLOCK_SIZE)
          CopyMemory(*in+c, @temp_iv(), #DES_BLOCK_SIZE) ; update IV
        EndIf
        CopyMemory(@temp_out(), *out+c, #DES_BLOCK_SIZE)
        c=c+#DES_BLOCK_SIZE
      Wend
      result=1
    EndIf
    ProcedureReturn result
  EndProcedure
  
  Procedure.i TripleDESEncryptCBC(*in, length.i, *out, *iv, *key, key_length.i)
    Define result.i=0
    MakeSubkeys(*key, key_length, #DES_ENCRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_ENCRYPT, #True)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  Procedure.i TripleDESDecryptCBC(*in, length.i, *out, *iv, *key, key_length.i)
    Define result.i=0
    MakeSubkeys(*key, key_length, #DES_DECRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_DECRYPT, #True)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  ;- Encryption suite procedures
  
  Procedure.i DESEncryptCBC(*in, length.i, *out, *iv, *key)
    Define result.i=0
    MakeSubkeys(*key, 8, #DES_ENCRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_ENCRYPT, #False)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  Procedure.i DESDecryptCBC(*in, length.i, *out, *iv, *key)
    Define result.i=0
    MakeSubkeys(*key, 8, #DES_DECRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_DECRYPT, #False)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  Procedure.i TripleDES112EncryptCBC(*in, length.i, *out, *iv, *key)
    Define result.i=0
    MakeSubkeys(*key, 16, #DES_ENCRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_ENCRYPT, #True)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  Procedure.i TripleDES112DecryptCBC(*in, length.i, *out, *iv, *key)
    Define result.i=0
    MakeSubkeys(*key, 16, #DES_DECRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_DECRYPT, #True)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  Procedure.i TripleDES168EncryptCBC(*in, length.i, *out, *iv, *key)
    Define result.i=0
    MakeSubkeys(*key, 24, #DES_ENCRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_ENCRYPT, #True)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure
  
  Procedure.i TripleDES168DecryptCBC(*in, length.i, *out, *iv, *key)
    Define result.i=0
    MakeSubkeys(*key, 24, #DES_DECRYPT)
    result = ProcessBufferCBC(*in, length, *out, *iv, #DES_DECRYPT, #True)
    ClearSubkeys()
    ProcedureReturn result
  EndProcedure   
  
  Procedure.i SelfTest()
    Dim test_plaintext.a(8)
    Dim test_ciphertext.a(8)
    Dim test_expected.a(8)
    Dim test_key.a(24)
    Dim test_IV.a(8)
    Define test_s.s
    Define *in_test, *out_test
    Define test_length.i, result_length.i
    Define test_result.i=0
    Define result.i=1
    ; Test basic block operation
    Debug "Testing block operation..."
    CopyMemory(?Test_Block, @test_plaintext(), 8)
    CopyMemory(?test_expected, @test_expected(), 8)
    CopyMemory(?Test_Key, @test_key(), 24)
    MakeSubkeys(@test_key(), 8, #DES_ENCRYPT)
    ProcessBlock(test_plaintext(), test_ciphertext())
    If CompareMemory(@test_expected(), @test_ciphertext(), 8):Debug "Block encrypt OK":
      Else:Debug "Block encrypt fail":Result=0:EndIf 
    CopyMemory(?Test_block, @test_expected(), 8)
    CopyMemory(@test_ciphertext(), @test_plaintext(), 8)
    MakeSubkeys(@test_key(), 8, #DES_DECRYPT)
    ProcessBlock(test_plaintext(), test_ciphertext())
    If CompareMemory(@test_expected(), @test_ciphertext(), 8):Debug "Block decrypt OK":
      Else:Debug "Block decrypt fail":Result=0:EndIf
    ; Test CBC procedures
    MakeIV(@test_IV())
    test_s = "In cryptography, Triple DES (3DES) is the common name for the Triple Data Encryption Algorithm (TDEA or Triple DEA) symmetric-key block cipher, which applies the Data Encryption Standard (DES) cipher algorithm three times to each data block."
    ; Test DES CBC        
    test_length = StringByteLength(test_s)
    result_length = test_length
    If result_length % 8
      result_length=result_length + 8 - (test_length % 8)
    EndIf
    *in_test=AllocateMemory(result_length)
    *out_test=AllocateMemory(result_length)
    CopyMemory(@test_s, *in_test, test_length)
    Debug "Testing DES (56-bit) CBC..."
    test_result = DESEncryptCBC(*in_test, result_length, *out_test, @test_IV(), @test_key())
    CopyMemory(*out_test, *in_test, result_length)
    If test_result
      test_result = DESDecryptCBC(*in_test, result_length, *out_test, @test_IV(), @test_key())
    EndIf
    If test_result
      test_result = CompareMemory(*out_test, @test_s, test_length)
    EndIf
    If test_result:Debug "DES CBC OK":
      Else: Debug "DES CBC fail": Result=0:EndIf
    ; Test 3DES CBC
    For key_size=1 To 3
      Debug "Testing 3DES (" + Str(key_size * 56) + "-bit) CBC..."
      FillMemory(*in_test, result_length)
      CopyMemory(@test_s, *in_test, test_length)
      test_result = TripleDESEncryptCBC(*in_test, result_length, *out_test, @test_IV(), @test_key(), key_size*8)
      CopyMemory(*out_test, *in_test, result_length)
      If test_result
        test_result = TripleDESDecryptCBC(*in_test, result_length, *out_test, @test_IV(), @test_key(), key_size*8)
      EndIf
      If test_result
        test_result = CompareMemory(*out_test, @test_s, test_length)
      EndIf
      If test_result:Debug "3DES (" + Str(key_size * 56) + "-bit) CBC OK":
        Else: Debug "3DES (" + Str(key_size * 56) + "-bit) CBC fail": Result=0:EndIf
    Next key_size
    If Result:Debug "Self test OK":Else:Debug "Self test FAIL":EndIf
    FreeMemory(*in_test)
    FreeMemory(*out_test)
    ProcedureReturn result
  EndProcedure
  
  Initialise()  
  
  CompilerIf #PB_Compiler_IsMainFile
    SelfTest()
  CompilerEndIf  
  
  ;- Data Section
  
  DataSection
    
    Test_key:
    Data.a $5B, $5A, $57, $67, $6A, $56, $67, $6E, $2A, $3A, $11, $37, $6F, $22, $33, $44, $55, $66, $77, $88, $99, $AA, $BB, $CC
    Test_block:
    Data.a $67, $5A, $69, $67, $5E, $5A, $6B, $5A
    test_expected:
    Data.a $97, $4A, $FF, $BF, $86, $02, $2D, $1F
    
    DES_IP_Table:  ; initial permutation of the data
    Data.a 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
           62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
           57, 49, 41, 33, 25, 17,  9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
           61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
    
    DES_FP_Table:  ; final permutation of the data
    Data.a 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
           38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
           36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
           34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41,  9, 49, 17, 57, 25
    
    DES_PC1_Table:  ;permuted choice 1
    Data.a 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2,
           59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
           63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6,
           61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
    
    DES_PC2_Table:  ;permuted choice 2
    Data.a 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
           23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
           41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
           44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
    
    DES_expansion_table:  ; for expanding 32 bits into 48
    Data.a 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
           8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
           16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
           24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
    
    ; Substitution boxes
    DES_sbox1:
    Data.a 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
           3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
           4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
           15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
    
    DES_sbox2:
    Data.a 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
           9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
           0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
           5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
    
    DES_sbox3:
    Data.a 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
           1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
           13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
           11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
    
    DES_sbox4:
    Data.a 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
           1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
           10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
           15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
    
    DES_sbox5:
    Data.a 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
           8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
           4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
           15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
    
    DES_sbox6:
    Data.a 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
           0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
           9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
           7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
    
    DES_sbox7:
    Data.a 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
           3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
           1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
           10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
    
    DES_sbox8:
    Data.a 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
           10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
           7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
           0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
    
    DES_p_table:  ; substitution block permutation table
    Data.a 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
           2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
    
  EndDataSection
  
EndModule

Last edited by coco2 on Wed Jun 04, 2014 9:10 am, edited 4 times in total.
Fred
Administrator
Administrator
Posts: 18247
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: DES/3DES Cipher Module

Post by Fred »

Nice work !
marroh
User
User
Posts: 72
Joined: Wed Aug 06, 2008 8:21 am

Re: DES/3DES Cipher Module

Post by marroh »

Thanks for share! :D
PureBASIC v5.41 LTS , Windows v8.1 x64
Forget UNICODE - Keep it BASIC !
GoodNPlenty
Enthusiast
Enthusiast
Posts: 112
Joined: Wed May 13, 2009 8:38 am
Location: Arizona, USA

Re: DES/3DES Cipher Module

Post by GoodNPlenty »

Well Done! Thank You for sharing.
harkon
Enthusiast
Enthusiast
Posts: 217
Joined: Wed Nov 23, 2005 5:48 pm

Re: DES/3DES Cipher Module

Post by harkon »

Thank you for sharing this.
Missed it by that much!!
HK
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: DES/3DES Cipher Module

Post by davido »

Nice one!

Thank you for sharing. :D
DE AA EB
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: DES/3DES Cipher Module

Post by luis »

I think there are some problems.

1) It does seem to work in unicode only, if I run the example in ASCII mode the self test fails.

2) Even if it seems to work in unicode, in reality it causes a buffer overflow if the input and consequently the output buffer are not a multiple of #DES_BLOCK_SIZE.

In that case

CopyMemory(@temp_out(), *out+c, #DES_BLOCK_SIZE)

in ProcessBufferCBC()

causes a buffer overflow in *out, since at the last iteration 'c + #DES_BLOCK_SIZE' is bigger than 'length'.

In the example the test string is 241 chars so it does write beyond the buffer.

Changing the test string to "1234567In cryptography...", 248 is a multiple of #DES_BLOCK_SIZE and it does work again.

Also confirmed by trying it with the Purifier. I've used the latest PB beta on x86, Win.
"Have you tried turning it off and on again ?"
coco2
Enthusiast
Enthusiast
Posts: 461
Joined: Mon Nov 25, 2013 5:38 am
Location: Australia

Re: DES/3DES Cipher Module

Post by coco2 »

Thank you Luis, I've only started programming again after some decades :). I believe since at this level padding is not done (padding schemes vary and are not linked to a particular cipher), that the ProcessBufferCBC routine should expect an input with a multiple of 8 (the DES block size) anyway. I think it would be best if the ProcessBufferCBC routine returned a failed result if the *buffer length is not a multiple of 8.
Post Reply