Native Blowfish encryption (x86) (5 Feb 2013)

Share your advanced PureBasic knowledge/code with the community.
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Native Blowfish encryption (x86) (5 Feb 2013)

Post by Inf0Byt3 »

For the sake of diversity and security-related paranoia, here's a native PureBasic implementation for the Blowfish encryption algorithm. As you probably know, it is very popular and considered secure as of 2013, not to mention free and unpatented. The code below complies with the official test vectors and implements both ECB and CBC encryption modes as well as 2 types of common padding schemes. You can find 3 tests (for ECB, CBC and stress) in the post below.

The only thing with the current implementation is that it's not too fast. In a raw test done on an Athlon64 clocked at 2000 MHz, the encryption tops at aprox. 8.3 MB / s. Any ideas for speed improvements are appreciated.

For now the code was tested only on Windows XP, x86, but it should work on Linux as well :).

Enjoy!

BE_BlowFish.pbi:

Code: Select all


;///////////////////////////////////////////////////////////////////////////////
;//
;// Blowfish Encryption algorithm for PureBasic 5.10+
;// 
;// Details:
;// -Block cipher: 64-bit block
;// -Variable key length: 32 bits To 448 bits
;// -Designed by Bruce Schneier
;// -Much faster than DES And IDEA
;// -Unpatented and royalty-free
;// -No license required
;// -Free source code available 
;// 
;// According to http://www.schneier.com/blowfish.html
;// Blowfish was designed in 1993 by Bruce Schneier as a fast, free alternative to
;// existing encryption algorithms. Since then it has been analyzed considerably,
;// and it is slowly gaining acceptance as a strong encryption algorithm. Blowfish
;// is unpatented and license-free, and is available free for all uses. 
;//
;// Notes:
;// 
;// Note 1. This implementation complies with the test vectors available here:
;// http://www.schneier.com/code/vectors.txt
;//
;// Note 2. No test have been made on x64! This code was tested only with the
;// x86 version of PureBasic 5.10b.
;//
;// Note 3. The BlowfishEncoder and BlowfishDecoder functions will convert the
;// data from little-endian to big-endian for the encryption / decryption then
;// back to little-endian. Thanks to Roger "Rescator" Hågensen for his great
;// little procedure:
;// http://www.purebasic.fr/english/viewtopic.php?t=14524
;//
;// Note 4. The BlowfishEncoder and BlowfishDecoder functions implement buffer
;// padding according to RFC2630: each padding byte is the pad count (8 extra
;// added if size is already a multiple of 8) by default.
;// 
;///////////////////////////////////////////////////////////////////////////////
;// 
;// This code is released under the Zlib license:
;// 
;// Copyright (c) 2013 Alexandru Trutia
;// 
;// This software is provided 'as-is', without any express or implied
;// warranty. In no event will the authors be held liable for any damages
;// arising from the use of this software.
;// 
;// Permission is granted to anyone to use this software for any purpose,
;// including commercial applications, and to alter it and redistribute it
;// freely, subject to the following restrictions:
;// 
;//    1. The origin of this software must not be misrepresented; you must not
;//    claim that you wrote the original software. If you use this software
;//    in a product, an acknowledgment in the product documentation would be
;//    appreciated but is not required.
;// 
;//    2. Altered source versions must be plainly marked as such, and must not
;//    be misrepresented as being the original software.
;// 
;//    3. This notice may not be removed or altered from any source
;//    distribution.
;// 
;///////////////////////////////////////////////////////////////////////////////
;// 
;// Changes:
;// 
;// * 05 Feb 2013:
;//   - First release
;//
;///////////////////////////////////////////////////////////////////////////////

;{ Explicit
EnableExplicit
;}

;{ Constants
Enumeration -7
  #BF_Error_DataLengthError
  #BF_Error_InvalidIVBuffer
  #BF_Error_InvalidKeySize
  #BF_Error_InvalidKeyBuffer
  #BF_Error_BadBufferSize
  #BF_Error_InvalidBuffer
  #BF_Error_OutOfMemory
  #BF_Error_InitKey
  #BF_Error_OK
EndEnumeration
Enumeration

  #BF_CBC             ;Cipher Block Chaining mode, recommended. It uses a 64-bit (8 byte) initialization vector

  #BF_ECB             ;Electronic CodeBook mode, not recommended. It doesn't use chaining of an initialization vector

EndEnumeration
Enumeration

  #BF_Padding_Nulls   ;NOT recommended if the data contains nulls! Use #BF_Padding_RFC2630 below to be safe! This method
                      ;works only with ASCII text!

  #BF_Padding_RFC2630 ;Recommended! Described in PKCS#5, PKCS#7 and RFC 3852 Section 6.3 (formerly RFC 3369 and RFC 2630)
                      ;It works with any type of data, including that which contains nulls.

EndEnumeration
;}

;{ Structures
Structure BF_Context
  PB.l[18]
  S0.l[256]
  S1.l[256]
  S2.l[256]
  S3.l[256]
EndStructure
Structure BF_Byte
  b.b[0]
EndStructure
Structure BF_Long
  l.l[0]
EndStructure
Structure BF_LargeInt
  L.l[2]
EndStructure
Structure BF_Data
  *Output
  OutputLength.i
  ErrorCode.i
EndStructure
;}

;{ Blowfish S-Boxes
DataSection

  BF_PB:
  Data.l $243F6A88, $85A308D3, $13198A2E, $03707344, $A4093822, $299F31D0, $082EFA98, $EC4E6C89
  Data.l $452821E6, $38D01377, $BE5466CF, $34E90C6C, $C0AC29B7, $C97C50DD, $3F84D5B5, $B5470917
  Data.l $9216D5D9, $8979FB1B

  BF_S0:
  Data.l $D1310BA6, $98DFB5AC, $2FFD72DB, $D01ADFB7, $B8E1AFED, $6A267E96, $BA7C9045, $F12C7F99
  Data.l $24A19947, $B3916CF7, $0801F2E2, $858EFC16, $636920D8, $71574E69, $A458FEA3, $F4933D7E
  Data.l $0D95748F, $728EB658, $718BCD58, $82154AEE, $7B54A41D, $C25A59B5, $9C30D539, $2AF26013
  Data.l $C5D1B023, $286085F0, $CA417918, $B8DB38EF, $8E79DCB0, $603A180E, $6C9E0E8B, $B01E8A3E
  Data.l $D71577C1, $BD314B27, $78AF2FDA, $55605C60, $E65525F3, $AA55AB94, $57489862, $63E81440
  Data.l $55CA396A, $2AAB10B6, $B4CC5C34, $1141E8CE, $A15486AF, $7C72E993, $B3EE1411, $636FBC2A
  Data.l $2BA9C55D, $741831F6, $CE5C3E16, $9B87931E, $AFD6BA33, $6C24CF5C, $7A325381, $28958677
  Data.l $3B8F4898, $6B4BB9AF, $C4BFE81B, $66282193, $61D809CC, $FB21A991, $487CAC60, $5DEC8032
  Data.l $EF845D5D, $E98575B1, $DC262302, $EB651B88, $23893E81, $D396ACC5, $0F6D6FF3, $83F44239
  Data.l $2E0B4482, $A4842004, $69C8F04A, $9E1F9B5E, $21C66842, $F6E96C9A, $670C9C61, $ABD388F0
  Data.l $6A51A0D2, $D8542F68, $960FA728, $AB5133A3, $6EEF0B6C, $137A3BE4, $BA3BF050, $7EFB2A98
  Data.l $A1F1651D, $39AF0176, $66CA593E, $82430E88, $8CEE8619, $456F9FB4, $7D84A5C3, $3B8B5EBE
  Data.l $E06F75D8, $85C12073, $401A449F, $56C16AA6, $4ED3AA62, $363F7706, $1BFEDF72, $429B023D
  Data.l $37D0D724, $D00A1248, $DB0FEAD3, $49F1C09B, $075372C9, $80991B7B, $25D479D8, $F6E8DEF7
  Data.l $E3FE501A, $B6794C3B, $976CE0BD, $04C006BA, $C1A94FB6, $409F60C4, $5E5C9EC2, $196A2463
  Data.l $68FB6FAF, $3E6C53B5, $1339B2EB, $3B52EC6F, $6DFC511F, $9B30952C, $CC814544, $AF5EBD09
  Data.l $BEE3D004, $DE334AFD, $660F2807, $192E4BB3, $C0CBA857, $45C8740F, $D20B5F39, $B9D3FBDB
  Data.l $5579C0BD, $1A60320A, $D6A100C6, $402C7279, $679F25FE, $FB1FA3CC, $8EA5E9F8, $DB3222F8
  Data.l $3C7516DF, $FD616B15, $2F501EC8, $AD0552AB, $323DB5FA, $FD238760, $53317B48, $3E00DF82
  Data.l $9E5C57BB, $CA6F8CA0, $1A87562E, $DF1769DB, $D542A8F6, $287EFFC3, $AC6732C6, $8C4F5573
  Data.l $695B27B0, $BBCA58C8, $E1FFA35D, $B8F011A0, $10FA3D98, $FD2183B8, $4AFCB56C, $2DD1D35B
  Data.l $9A53E479, $B6F84565, $D28E49BC, $4BFB9790, $E1DDF2DA, $A4CB7E33, $62FB1341, $CEE4C6E8
  Data.l $EF20CADA, $36774C01, $D07E9EFE, $2BF11FB4, $95DBDA4D, $AE909198, $EAAD8E71, $6B93D5A0
  Data.l $D08ED1D0, $AFC725E0, $8E3C5B2F, $8E7594B7, $8FF6E2FB, $F2122B64, $8888B812, $900DF01C
  Data.l $4FAD5EA0, $688FC31C, $D1CFF191, $B3A8C1AD ,$2F2F2218, $BE0E1777, $EA752DFE, $8B021FA1
  Data.l $E5A0CC0F, $B56F74E8, $18ACF3D6, $CE89E299, $B4A84FE0, $FD13E0B7, $7CC43B81, $D2ADA8D9
  Data.l $165FA266, $80957705, $93CC7314, $211A1477, $E6AD2065, $77B5FA86, $C75442F5, $FB9D35CF
  Data.l $EBCDAF0C, $7B3E89A0, $D6411BD3, $AE1E7E49, $00250E2D, $2071B35E, $226800BB, $57B8E0AF
  Data.l $2464369B, $F009B91E, $5563911D, $59DFA6AA, $78C14389, $D95A537F, $207D5BA2, $02E5B9C5
  Data.l $83260376, $6295CFA9, $11C81968, $4E734A41, $B3472DCA, $7B14A94A, $1B510052, $9A532915
  Data.l $D60F573F, $BC9BC6E4, $2B60A476, $81E67400, $08BA6FB5, $571BE91F, $F296EC6B, $2A0DD915
  Data.l $B6636521, $E7B9F9B6, $FF34052E, $C5855664, $53B02D5D, $A99F8FA1, $08BA4799, $6E85076A

  BF_S1:
  Data.l $4B7A70E9, $B5B32944, $DB75092E, $C4192623, $AD6EA6B0, $49A7DF7D, $9CEE60B8, $8FEDB266
  Data.l $ECAA8C71, $699A17FF, $5664526C, $C2B19EE1, $193602A5, $75094C29, $A0591340, $E4183A3E
  Data.l $3F54989A, $5B429D65, $6B8FE4D6, $99F73FD6, $A1D29C07, $EFE830F5, $4D2D38E6, $F0255DC1
  Data.l $4CDD2086, $8470EB26, $6382E9C6, $021ECC5E, $09686B3F, $3EBAEFC9, $3C971814, $6B6A70A1
  Data.l $687F3584, $52A0E286, $B79C5305, $AA500737, $3E07841C, $7FDEAE5C, $8E7D44EC, $5716F2B8
  Data.l $B03ADA37, $F0500C0D, $F01C1F04, $0200B3FF, $AE0CF51A, $3CB574B2, $25837A58, $DC0921BD
  Data.l $D19113F9, $7CA92FF6, $94324773, $22F54701, $3AE5E581, $37C2DADC, $C8B57634, $9AF3DDA7
  Data.l $A9446146, $0FD0030E, $ECC8C73E, $A4751E41, $E238CD99, $3BEA0E2F, $3280BBA1, $183EB331
  Data.l $4E548B38, $4F6DB908, $6F420D03, $F60A04BF, $2CB81290, $24977C79, $5679B072, $BCAF89AF
  Data.l $DE9A771F, $D9930810, $B38BAE12, $DCCF3F2E, $5512721F, $2E6B7124, $501ADDE6, $9F84CD87
  Data.l $7A584718, $7408DA17, $BC9F9ABC, $E94B7D8C, $EC7AEC3A, $DB851DFA, $63094366, $C464C3D2
  Data.l $EF1C1847, $3215D908, $DD433B37, $24C2BA16, $12A14D43, $2A65C451, $50940002, $133AE4DD
  Data.l $71DFF89E, $10314E55, $81AC77D6, $5F11199B, $043556F1, $D7A3C76B, $3C11183B, $5924A509
  Data.l $F28FE6ED, $97F1FBFA, $9EBABF2C, $1E153C6E, $86E34570, $EAE96FB1, $860E5E0A, $5A3E2AB3
  Data.l $771FE71C, $4E3D06FA, $2965DCB9, $99E71D0F, $803E89D6, $5266C825, $2E4CC978, $9C10B36A
  Data.l $C6150EBA, $94E2EA78, $A5FC3C53, $1E0A2DF4, $F2F74EA7, $361D2B3D, $1939260F, $19C27960
  Data.l $5223A708, $F71312B6, $EBADFE6E, $EAC31F66, $E3BC4595, $A67BC883, $B17F37D1, $018CFF28
  Data.l $C332DDEF, $BE6C5AA5, $65582185, $68AB9802, $EECEA50F, $DB2F953B, $2AEF7DAD, $5B6E2F84
  Data.l $1521B628, $29076170, $ECDD4775, $619F1510, $13CCA830, $EB61BD96, $0334FE1E, $AA0363CF
  Data.l $B5735C90, $4C70A239, $D59E9E0B, $CBAADE14, $EECC86BC, $60622CA7, $9CAB5CAB, $B2F3846E
  Data.l $648B1EAF, $19BDF0CA, $A02369B9, $655ABB50, $40685A32, $3C2AB4B3, $319EE9D5, $C021B8F7
  Data.l $9B540B19, $875FA099, $95F7997E, $623D7DA8, $F837889A, $97E32D77, $11ED935F, $16681281
  Data.l $0E358829, $C7E61FD6, $96DEDFA1, $7858BA99, $57F584A5, $1B227263, $9B83C3FF, $1AC24696
  Data.l $CDB30AEB, $532E3054, $8FD948E4, $6DBC3128, $58EBF2EF, $34C6FFEA, $FE28ED61, $EE7C3C73
  Data.l $5D4A14D9, $E864B7E3, $42105D14, $203E13E0, $45EEE2B6, $A3AAABEA, $DB6C4F15, $FACB4FD0
  Data.l $C742F442, $EF6ABBB5, $654F3B1D, $41CD2105, $D81E799E, $86854DC7, $E44B476A, $3D816250
  Data.l $CF62A1F2, $5B8D2646, $FC8883A0, $C1C7B6A3, $7F1524C3, $69CB7492, $47848A0B, $5692B285
  Data.l $095BBF00, $AD19489D, $1462B174, $23820E00, $58428D2A, $0C55F5EA, $1DADF43E, $233F7061
  Data.l $3372F092, $8D937E41, $D65FECF1, $6C223BDB, $7CDE3759, $CBEE7460, $4085F2A7, $CE77326E
  Data.l $A6078084, $19F8509E, $E8EFD855, $61D99735, $A969A7AA, $C50C06C2, $5A04ABFC, $800BCADC
  Data.l $9E447A2E, $C3453484, $FDD56705, $0E1E9EC9, $DB73DBD3, $105588CD, $675FDA79, $E3674340
  Data.l $C5C43465, $713E38D8, $3D28F89E, $F16DFF20, $153E21E7, $8FB03D4A, $E6E39F2B, $DB83ADF7

  BF_S2:
  Data.l $E93D5A68, $948140F7, $F64C261C, $94692934, $411520F7, $7602D4F7, $BCF46B2E, $D4A20068
  Data.l $D4082471, $3320F46A, $43B7D4B7, $500061AF, $1E39F62E, $97244546, $14214F74, $BF8B8840
  Data.l $4D95FC1D, $96B591AF, $70F4DDD3, $66A02F45, $BFBC09EC, $03BD9785, $7FAC6DD0, $31CB8504
  Data.l $96EB27B3, $55FD3941, $DA2547E6, $ABCA0A9A, $28507825, $530429F4, $0A2C86DA, $E9B66DFB
  Data.l $68DC1462, $D7486900, $680EC0A4, $27A18DEE, $4F3FFEA2, $E887AD8C, $B58CE006, $7AF4D6B6
  Data.l $AACE1E7C, $D3375FEC, $CE78A399, $406B2A42, $20FE9E35, $D9F385B9, $EE39D7AB, $3B124E8B
  Data.l $1DC9FAF7, $4B6D1856, $26A36631, $EAE397B2, $3A6EFA74, $DD5B4332, $6841E7F7, $CA7820FB
  Data.l $FB0AF54E, $D8FEB397, $454056AC, $BA489527, $55533A3A, $20838D87, $FE6BA9B7, $D096954B
  Data.l $55A867BC, $A1159A58, $CCA92963, $99E1DB33, $A62A4A56, $3F3125F9, $5EF47E1C, $9029317C
  Data.l $FDF8E802, $04272F70, $80BB155C, $05282CE3, $95C11548, $E4C66D22, $48C1133F, $C70F86DC
  Data.l $07F9C9EE, $41041F0F, $404779A4, $5D886E17, $325F51EB, $D59BC0D1, $F2BCC18F, $41113564
  Data.l $257B7834, $602A9C60, $DFF8E8A3, $1F636C1B, $0E12B4C2, $02E1329E, $AF664FD1, $CAD18115
  Data.l $6B2395E0, $333E92E1, $3B240B62, $EEBEB922, $85B2A20E, $E6BA0D99, $DE720C8C, $2DA2F728
  Data.l $D0127845, $95B794FD, $647D0862, $E7CCF5F0, $5449A36F, $877D48FA, $C39DFD27, $F33E8D1E
  Data.l $0A476341, $992EFF74, $3A6F6EAB, $F4F8FD37, $A812DC60, $A1EBDDF8, $991BE14C, $DB6E6B0D
  Data.l $C67B5510, $6D672C37, $2765D43B, $DCD0E804, $F1290DC7, $CC00FFA3, $B5390F92, $690FED0B
  Data.l $667B9FFB, $CEDB7D9C, $A091CF0B, $D9155EA3, $BB132F88, $515BAD24, $7B9479BF, $763BD6EB
  Data.l $37392EB3, $CC115979, $8026E297, $F42E312D, $6842ADA7, $C66A2B3B, $12754CCC, $782EF11C
  Data.l $6A124237, $B79251E7, $06A1BBE6, $4BFB6350, $1A6B1018, $11CAEDFA, $3D25BDD8, $E2E1C3C9
  Data.l $44421659, $0A121386, $D90CEC6E, $D5ABEA2A, $64AF674E, $DA86A85F, $BEBFE988, $64E4C3FE
  Data.l $9DBC8057, $F0F7C086, $60787BF8, $6003604D, $D1FD8346, $F6381FB0, $7745AE04, $D736FCCC
  Data.l $83426B33, $F01EAB71, $B0804187, $3C005E5F, $77A057BE, $BDE8AE24, $55464299, $BF582E61
  Data.l $4E58F48F, $F2DDFDA2, $F474EF38, $8789BDC2, $5366F9C3, $C8B38E74, $B475F255, $46FCD9B9
  Data.l $7AEB2661, $8B1DDF84, $846A0E79, $915F95E2, $466E598E, $20B45770, $8CD55591, $C902DE4C
  Data.l $B90BACE1, $BB8205D0, $11A86248, $7574A99E, $B77F19B6, $E0A9DC09, $662D09A1, $C4324633
  Data.l $E85A1F02, $09F0BE8C, $4A99A025, $1D6EFE10, $1AB93D1D, $0BA5A4DF, $A186F20F, $2868F169
  Data.l $DCB7DA83, $573906FE, $A1E2CE9B, $4FCD7F52, $50115E01, $A70683FA, $A002B5C4, $0DE6D027
  Data.l $9AF88C27, $773F8641, $C3604C06, $61A806B5, $F0177A28, $C0F586E0, $006058AA, $30DC7D62
  Data.l $11E69ED7, $2338EA63, $53C2DD94, $C2C21634, $BBCBEE56, $90BCB6DE, $EBFC7DA1, $CE591D76
  Data.l $6F05E409, $4B7C0188, $39720A3D, $7C927C24, $86E3725F, $724D9DB9, $1AC15BB4, $D39EB8FC
  Data.l $ED545578, $08FCA5B5, $D83D7CD3, $4DAD0FC4, $1E50EF5E, $B161E6F8, $A28514D9, $6C51133C
  Data.l $6FD5C7E7, $56E14EC4, $362ABFCE, $DDC6C837, $D79A3234, $92638212, $670EFA8E, $406000E0

  BF_S3:
  Data.l $3A39CE37, $D3FAF5CF, $ABC27737, $5AC52D1B, $5CB0679E, $4FA33742, $D3822740, $99BC9BBE
  Data.l $D5118E9D, $BF0F7315, $D62D1C7E, $C700C47B, $B78C1B6B, $21A19045, $B26EB1BE, $6A366EB4
  Data.l $5748AB2F, $BC946E79, $C6A376D2, $6549C2C8, $530FF8EE, $468DDE7D, $D5730A1D, $4CD04DC6
  Data.l $2939BBDB, $A9BA4650, $AC9526E8, $BE5EE304, $A1FAD5F0, $6A2D519A, $63EF8CE2, $9A86EE22
  Data.l $C089C2B8, $43242EF6, $A51E03AA, $9CF2D0A4, $83C061BA, $9BE96A4D, $8FE51550, $BA645BD6
  Data.l $2826A2F9, $A73A3AE1, $4BA99586, $EF5562E9, $C72FEFD3, $F752F7DA, $3F046F69, $77FA0A59
  Data.l $80E4A915, $87B08601, $9B09E6AD, $3B3EE593, $E990FD5A, $9E34D797, $2CF0B7D9, $022B8B51
  Data.l $96D5AC3A, $017DA67D, $D1CF3ED6, $7C7D2D28, $1F9F25CF, $ADF2B89B, $5AD6B472, $5A88F54C
  Data.l $E029AC71, $E019A5E6, $47B0ACFD, $ED93FA9B, $E8D3C48D, $283B57CC, $F8D56629, $79132E28
  Data.l $785F0191, $ED756055, $F7960E44, $E3D35E8C, $15056DD4, $88F46DBA, $03A16125, $0564F0BD
  Data.l $C3EB9E15, $3C9057A2, $97271AEC, $A93A072A, $1B3F6D9B, $1E6321F5, $F59C66FB, $26DCF319
  Data.l $7533D928, $B155FDF5, $03563482, $8ABA3CBB, $28517711, $C20AD9F8, $ABCC5167, $CCAD925F
  Data.l $4DE81751, $3830DC8E, $379D5862, $9320F991, $EA7A90C2, $FB3E7BCE, $5121CE64, $774FBE32
  Data.l $A8B6E37E, $C3293D46, $48DE5369, $6413E680, $A2AE0810, $DD6DB224, $69852DFD, $09072166
  Data.l $B39A460A, $6445C0DD, $586CDECF, $1C20C8AE, $5BBEF7DD, $1B588D40, $CCD2017F, $6BB4E3BB
  Data.l $DDA26A7E, $3A59FF45, $3E350A44, $BCB4CDD5, $72EACEA8, $FA6484BB, $8D6612AE, $BF3C6F47
  Data.l $D29BE463, $542F5D9E, $AEC2771B, $F64E6370, $740E0D8D, $E75B1357, $F8721671, $AF537D5D
  Data.l $4040CB08, $4EB4E2CC, $34D2466A, $0115AF84, $E1B00428, $95983A1D, $06B89FB4, $CE6EA048
  Data.l $6F3F3B82, $3520AB82, $011A1D4B, $277227F8, $611560B1, $E7933FDC, $BB3A792B, $344525BD
  Data.l $A08839E1, $51CE794B, $2F32C9B7, $A01FBAC9, $E01CC87E, $BCC7D1F6, $CF0111C3, $A1E8AAC7
  Data.l $1A908749, $D44FBD9A, $D0DADECB, $D50ADA38, $0339C32A, $C6913667, $8DF9317C, $E0B12B4F
  Data.l $F79E59B7, $43F5BB3A, $F2D519FF, $27D9459C, $BF97222C, $15E6FC2A, $0F91FC71, $9B941525
  Data.l $FAE59361, $CEB69CEB, $C2A86459, $12BAA8D1, $B6C1075E, $E3056A0C, $10D25065, $CB03A442
  Data.l $E0EC6E0E, $1698DB3B, $4C98A0BE, $3278E964, $9F1F9532, $E0D392DF, $D3A0342B, $8971F21E
  Data.l $1B0A7441, $4BA3348C, $C5BE7120, $C37632D8, $DF359F8D, $9B992F2E, $E60B6F47, $0FE3F11D
  Data.l $E54CDA54, $1EDAD891, $CE6279CF, $CD3E7E6F, $1618B166, $FD2C1D05, $848FD2C5, $F6FB2299
  Data.l $F523F357, $A6327623, $93A83531, $56CCCD02, $ACF08162, $5A75EBB5, $6E163697, $88D273CC
  Data.l $DE966292, $81B949D0, $4C50901B, $71C65614, $E6C6C7BD, $327A140A, $45E1D006, $C3F27B9A
  Data.l $C9AA53FD, $62A80F00, $BB25BFE2, $35BDD2F6, $71126905, $B2040222, $B6CBCF7C, $CD769C2B
  Data.l $53113EC0, $1640E3D3, $38ABBD60, $2547ADF0, $BA38209C, $F746CE76, $77AFA1C5, $20756060
  Data.l $85CBFE4E, $8AE88DD8, $7AAAF9B0, $4CF9AA7E, $1948C25C, $02FB8A8C, $01C36AE4, $D6EBE1F9
  Data.l $90D4F869, $A65CDEA0, $3F09252D, $C208E69F, $B74E6132, $CE77E25B, $578FDFE3, $3AC372E6

EndDataSection
;}

;-----------------------------------------------------------------------------------

Procedure.l Endian(val.l)
  !MOV Eax,dword[p.v_val]
  !BSWAP Eax
  ProcedureReturn
EndProcedure

;-----------------------------------------------------------------------------------

Procedure.s BF_PeekHEX(*Buffer.BF_Byte, Length) ;Read a HEX string from an address, for debugging
  Protected Loop, Result.s
  While Loop < Length
    Result + RSet(Hex(*Buffer\b[Loop] & $FF ,#PB_Byte), 2, "0")
    Loop + 1
  Wend
  ProcedureReturn Result
EndProcedure

Procedure BF_PokeHEX(*Buffer.BF_Byte, *HexString.BF_Byte, HexStringLen) ;Write a HEX string to an address, for debugging
  Protected Loop1, Byte1.b, Byte2.b, Counter1, Counter2
  Repeat
    Byte1 = *HexString\b[Counter1] - 48
    If Byte1 > 10 : Byte1 - 7 : EndIf
    Byte2 = *HexString\b[Counter1 + 1] - 48
    If Byte2 > 10 : Byte2 - 7 : EndIf
    *Buffer\b[Counter2] = (Byte1 * 16) + Byte2
    Counter1 + 2
    Counter2 + 1
    Loop1 + 2
  Until Counter1 = HexStringLen
  ProcedureReturn Counter2
EndProcedure

;-----------------------------------------------------------------------------------

Procedure BF_XorMemory(*Memory.BF_Byte, MemoryLength, *Key.BF_Byte, KeyLength) ;Needed for the CBC mode
  Protected i, j
  While i < MemoryLength
    If j = KeyLength : j = 0 : EndIf
    *Memory\b[i] ! (*Key\b[j] & $FF)
    i + 1 : j + 1
  Wend
EndProcedure

Procedure BF_EncBlock(*CTX.BF_Context, *Hi.LONG, *Lo.LONG) ;[!] Expects 4 + 4 bytes

  ;Vars
  Protected Loop

  ;Encrypt
  While Loop < 16
    *Hi\l ! *CTX\PB[Loop]
    *Lo\l ! (((*CTX\S0[(*Hi\l >> 24) & $FF] + *CTX\S1[(*Hi\l >> 16) & $FF]) ! *CTX\S2[(*Hi\l >> 8) & $FF]) + *CTX\S3[*Hi\l & $FF])
    Swap *Hi\l, *Lo\l
    Loop + 1
  Wend
	Swap *Hi\l, *Lo\l
  *Lo\l ! *CTX\PB[16]
  *Hi\l ! *CTX\PB[17]

  ;Return
  ProcedureReturn 1

EndProcedure

Procedure BF_DecBlock(*CTX.BF_Context, *Hi.LONG, *Lo.LONG) ;[!] Expects 4 + 4 bytes

  ;Vars
  Protected Loop

  ;Decrypt
  Loop = 17
  While Loop > 1
    *Hi\l ! *CTX\PB[Loop]
    *Lo\l ! (((*CTX\S0[(*Hi\l >> 24) & $FF] + *CTX\S1[(*Hi\l >> 16) & $FF]) ! *CTX\S2[(*Hi\l >> 8) & $FF]) + *CTX\S3[*Hi\l & $FF])
    Swap *Hi\l, *Lo\l
    Loop - 1
  Wend
	Swap *Hi\l, *Lo\l
  *Lo\l ! *CTX\PB[1]
  *Hi\l ! *CTX\PB[0]

  ;Return
  ProcedureReturn 1

EndProcedure

Procedure BF_InitKey(*CTX.BF_Context, *Key.BF_Byte, KeyLen) ;[!] Max 448 bits (56 bytes)

  ;Vars
  Protected Loop1, Loop2, Loop3, KData, HVal, LVal

  ;Check key len
	If KeyLen <= 0 Or KeyLen > 56 ;Max 448 bits
	  ProcedureReturn #BF_Error_InvalidKeySize
  EndIf

  ;Load the original S-boxes in the current context
  CopyMemory(?BF_PB, @*CTX\PB,  18 * 4)
  CopyMemory(?BF_S0, @*CTX\S0, 256 * 4)
  CopyMemory(?BF_S1, @*CTX\S1, 256 * 4)
  CopyMemory(?BF_S2, @*CTX\S2, 256 * 4)
  CopyMemory(?BF_S3, @*CTX\S3, 256 * 4)

  ;Init the key in the context
  For Loop1 = 0 To 17
    KData = 0
    For Loop3 = 0 To 3
      KData = ((KData << 8) | (*Key\b[Loop2] & $FF))
      Loop2 + 1
      If Loop2 >= KeyLen : Loop2 = 0 : EndIf
    Next
    *CTX\PB[Loop1] = *CTX\PB[Loop1] ! KData
  Next

  ;Init the S-boxes in the context
  For Loop1 = 0 To 17 Step 2
    BF_EncBlock(*CTX, @HVal, @LVal)
    *CTX\PB[Loop1]     = HVal
    *CTX\PB[Loop1 + 1] = LVal
  Next
  For Loop1 = 0 To 255 Step 2
    BF_EncBlock(*CTX, @HVal, @LVal)
    *CTX\S0[Loop1]     = HVal
    *CTX\S0[Loop1 + 1] = LVal
  Next
  For Loop1 = 0 To 255 Step 2
    BF_EncBlock(*CTX, @HVal, @LVal)
    *CTX\S1[Loop1]     = HVal
    *CTX\S1[Loop1 + 1] = LVal
  Next
  For Loop1 = 0 To 255 Step 2
    BF_EncBlock(*CTX, @HVal, @LVal)
    *CTX\S2[Loop1]     = HVal
    *CTX\S2[Loop1 + 1] = LVal
  Next
  For Loop1 = 0 To 255 Step 2
    BF_EncBlock(*CTX, @HVal, @LVal)
    *CTX\S3[Loop1]     = HVal
    *CTX\S3[Loop1 + 1] = LVal
  Next

  ;Return
  ProcedureReturn #BF_Error_OK

EndProcedure

;-----------------------------------------------------------------------------------

;[!] Notes:

;[1] These 2 functions return a pointer to a BF_Data structure which contains the output buffer, its size
;and error code.

;[2] Please look at the #BF_Padding_RFC2630 and #BF_Padding_Nulls constants in the header as they explain what
;padding methods are safe for different types of data

;[3] Regarding the encryption mode, CBC is much safer than ECB

;[4] CBC mode always expects an 8 byte IV. If you don't provide one, the functions will allocate an IV and fill it with 0s.

;[5] Padding is always added at encryption, even if the input size is multiple of the block size for Blowfish (8 bytes)

;[6] At decryption, make sure to use the same mode and padding scheme that was used for encryption

;[7] The returned buffer and structure must be freed manually when no longer needed

Procedure BlowfishEncoder(*Input, Size, *Key, KeyLen, *InitializationVector, Mode = #BF_CBC, Padding = #BF_Padding_RFC2630)
  
  ;Vars
  Protected *EncResult.BF_Data, *Encode.BF_LargeInt, AllocatedIV, CTX.BF_Context, OutBufferSize, *FinalInput, *FinalOutput
  Protected NeededPadding, Pad.b, AddPadding, TotalRounds, Encrypt, CurrentBlock
  
  ;Allocate memory for the return structure
  *EncResult = AllocateMemory(SizeOf(BF_Data))
  *Encode = AllocateMemory(8)
  If *EncResult <> 0 And *Encode <> 0
    If *Input <> 0
      If Size > 0
        If *Key <> 0
          If KeyLen > 0 And KeyLen <= 56
            If Mode = #BF_CBC
              If *InitializationVector = 0
                *InitializationVector = AllocateMemory(8) : FillMemory(*InitializationVector, 8, 0, #PB_Byte)
                AllocatedIV = 1
                Debug "[!] Blowfish in CBC mode needs an initialization vector!"
              EndIf
            EndIf
            ;Initialize the key
            If BF_InitKey(@CTX, *Key, KeyLen) = #BF_Error_OK
              ;Calculate padding and buffer sizes
              If Size % 8 = 0
                ;If the input size is multiple of 8, (out size) = (input size) + (8) (we pad anyway)
                OutBufferSize = Size + 8
              Else
                ;If the input size is NOT multiple of 8, (out size) = (input size) + (8) - (bytes needed to 8)
                OutBufferSize = Size + (8 - (Size % 8))
              EndIf
              ;Create the buffers
              *FinalInput = AllocateMemory(OutBufferSize)
              *FinalOutput = AllocateMemory(OutBufferSize)
              If *FinalInput <> 0 And *FinalOutput <> 0
                ;Fill with the original data
                CopyMemory(*Input, *FinalInput, Size)
                ;Pad the new input buffer
                NeededPadding = OutBufferSize - Size
                If Padding = #BF_Padding_RFC2630
                  Pad = NeededPadding
                ElseIf Padding = #BF_Padding_Nulls
                  Pad = 0
                EndIf
                For AddPadding = 0 To NeededPadding - 1
                  PokeB(*FinalInput + Size + AddPadding, Pad)
                Next
                ;Now encrypt the buffer
                TotalRounds = OutBufferSize / 8
                While Encrypt < TotalRounds
                  If Mode = #BF_CBC
                    If Encrypt = 0
                      ;For the first block, XOR with the IV
                      BF_XorMemory(*FinalInput + CurrentBlock, 8, *InitializationVector, 8)
                    Else
                      ;For the subsequent blocks, XOR with the previous block
                      BF_XorMemory(*FinalInput + CurrentBlock, 8, *FinalOutput + CurrentBlock - 8, 8)
                    EndIf
                  EndIf
                  ;Copy the 64-bit data to a temp buffer
                  CopyMemory(*FinalInput + CurrentBlock, *Encode, 8)
                  ;Convert to big endian
                  *Encode\L[0] = Endian(*Encode\L[0])
                  *Encode\L[1] = Endian(*Encode\L[1])
                  ;Encrypt the first and second halves: 4 bytes | 4 bytes
                  BF_EncBlock(@CTX, @*Encode\L[0], @*Encode\L[1])
                  ;Convert back to little endian
                  *Encode\L[0] = Endian(*Encode\L[0])
                  *Encode\L[1] = Endian(*Encode\L[1])
                  ;Then copy the encrypted data to the output buffer
                  CopyMemory(*Encode, *FinalOutput + CurrentBlock, 8)
                  CurrentBlock + 8
                  Encrypt + 1
                Wend
                ;Free the <temp> memory
                FreeMemory(*FinalInput)
                ;Return values
                *EncResult\ErrorCode = #BF_Error_OK
                *EncResult\Output = *FinalOutput
                *EncResult\OutputLength = OutBufferSize
              Else
                *EncResult\ErrorCode = #BF_Error_OutOfMemory
              EndIf
            Else
              *EncResult\ErrorCode = #BF_Error_InitKey
            EndIf
          Else
            *EncResult\ErrorCode = #BF_Error_InvalidKeySize
          EndIf
        Else
          *EncResult\ErrorCode = #BF_Error_InvalidKeyBuffer
        EndIf
      Else
        *EncResult\ErrorCode = #BF_Error_BadBufferSize
      EndIf
    Else
      *EncResult\ErrorCode = #BF_Error_InvalidBuffer
    EndIf
    FreeMemory(*Encode)
  Else
    *EncResult\ErrorCode = #BF_Error_OutOfMemory
    If *Encode <> 0 :  FreeMemory(*Encode) : EndIf
  EndIf
  
  ;Clean up
  If AllocatedIV = 1 And *InitializationVector <> 0 : FreeMemory(*InitializationVector) : EndIf
  
  ;Return
  ProcedureReturn *EncResult
  
EndProcedure

Procedure BlowfishDecoder(*Input, Size, *Key, KeyLen, *InitializationVector, Mode = #BF_CBC, Padding = #BF_Padding_RFC2630)
  
  ;Vars
  Protected *DecResult.BF_Data, *Decode.BF_LargeInt, AllocatedIV, CTX.BF_Context, *FinalOutput, TotalRounds, Decrypt
  Protected CurrentBlock, LastByte.b, TotalPadding
  
  ;Allocate memory for the return structure
  *DecResult = AllocateMemory(SizeOf(BF_Data))
  *Decode = AllocateMemory(8)
  If *DecResult <> 0 And *Decode <> 0
    If *Input <> 0
      If Size > 0
        If *Key <> 0
          If KeyLen > 0 And KeyLen <= 56
            If Mode = #BF_CBC
              If *InitializationVector = 0
                *InitializationVector = AllocateMemory(8) : FillMemory(*InitializationVector, 8, 0, #PB_Byte)
                AllocatedIV = 1
                Debug "[!] Blowfish in CBC mode needs an initialization vector!"
              EndIf
            EndIf
            ;Initialize the key
            If BF_InitKey(@CTX, *Key, KeyLen) = #BF_Error_OK
              ;Create the output buffer and a temp buffer
            *FinalOutput = AllocateMemory(Size)
            If *FinalOutput <> 0
              ;Now decrypt the buffer
              TotalRounds = Size / 8
              While Decrypt < TotalRounds
                ;Copy the 64-bit data to a temp buffer
                CopyMemory(*Input + CurrentBlock, *Decode, 8)
                ;Convert to big endian
                *Decode\L[0] = Endian(*Decode\L[0])
                *Decode\L[1] = Endian(*Decode\L[1])
                ;Decrypt the first and second halves: 4 bytes | 4 bytes
                BF_DecBlock(@CTX, @*Decode\L[0], @*Decode\L[1])
                ;Convert back to little endian
                *Decode\L[0] = Endian(*Decode\L[0])
                *Decode\L[1] = Endian(*Decode\L[1])
                ;Then copy the decrypted data to the output buffer
                CopyMemory(*Decode, *FinalOutput + CurrentBlock, 8)
                If Mode = #BF_CBC
                  If Decrypt = 0
                    ;For the first block, XOR with the IV
                    BF_XorMemory(*FinalOutput + CurrentBlock, 8, *InitializationVector, 8)
                  Else
                    ;For the subsequent blocks, XOR with the previous input block
                    BF_XorMemory(*FinalOutput + CurrentBlock, 8, *Input + CurrentBlock - 8, 8)
                  EndIf
                EndIf
                CurrentBlock + 8
                Decrypt + 1
              Wend
              ;Calculate padding
              If Padding = #BF_Padding_RFC2630
                LastByte = PeekB(*FinalOutput + Size - 1)
                TotalPadding = LastByte
              ElseIf Padding = #BF_Padding_Nulls
                LastByte = PeekB(*FinalOutput + Size - 1)
                If LastByte = 0
                  TotalPadding - 1
                  While LastByte = 0
                    LastByte = PeekB(*FinalOutput + Size - TotalPadding) & $FF
                    TotalPadding + 1
                  Wend
                EndIf
              EndIf
              ;Return values
              *DecResult\ErrorCode = #BF_Error_OK
              *DecResult\Output = *FinalOutput
              *DecResult\OutputLength = Size - TotalPadding
              Else
                *DecResult\ErrorCode = #BF_Error_OutOfMemory
              EndIf
            Else
              *DecResult\ErrorCode = #BF_Error_InitKey
            EndIf
          Else
            *DecResult\ErrorCode = #BF_Error_InvalidKeySize
          EndIf
        Else
          *DecResult\ErrorCode = #BF_Error_InvalidKeyBuffer
        EndIf
      Else
        *DecResult\ErrorCode = #BF_Error_BadBufferSize
      EndIf
    Else
      *DecResult\ErrorCode = #BF_Error_InvalidBuffer
    EndIf
    FreeMemory(*Decode)
  Else
    *DecResult\ErrorCode = #BF_Error_OutOfMemory
    If *Decode <> 0 :  FreeMemory(*Decode) : EndIf
  EndIf

  ;Clean up
  If AllocatedIV = 1 And *InitializationVector <> 0 : FreeMemory(*InitializationVector) : EndIf

  ;Return
  ProcedureReturn *DecResult

EndProcedure

;-----------------------------------------------------------------------------------
Examples below:
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Re: Native Blowfish encryption (x86) (5 Feb 2013)

Post by Inf0Byt3 »

StressTest.pb

Code: Select all

;[!] Run with debugger off!
DisableDebugger

;BF include
XIncludeFile "BE_BlowFish.pbi"

Define Bar.s, BarC, Loops, TotalLoops, KeyLen, *Key, OriginalLen, *Original, *IV, *EncResult.BF_Data
Define *DecResult.BF_Data, Success, Clr, Progress.f, StartTime, TotalTime, TotalData, Speed.f

TotalLoops = 128

#MinLen = 512 * 1024
#MaxLen = #MinLen * 2

OpenConsole()
EnableGraphicalConsole(1)

Bar = "-\|/"
BarC = 1
TotalData = 1

If OpenCryptRandom() = 0
  PrintN("Error opening random generator!"):Beep_(1500,500):Input():End
EndIf

StartTime = ElapsedMilliseconds()

For Loops = 1 To TotalLoops
  
  Progress = Loops / TotalLoops * 100
  TotalTime = ElapsedMilliseconds() - StartTime
  Speed.f = TotalData / (TotalTime + 1) / 1000

  ConsoleLocate(0, 0)
  PrintN("-------------------------------")
  PrintN("Blowfish for PureBasic stress test, min buffer len: "+Str(#MinLen)+" ("+Str(#MinLen / 1024)+" KB)")
  PrintN("Rounds: "+Str(Loops)+" of "+Str(TotalLoops)+", "+StrF(Progress,2)+"% ready "+Mid(Bar, BarC, 1)) : BarC + 1 : If BarC = 5 : BarC = 1 : EndIf
  PrintN("Elapsed: "+Str(TotalTime/1000)+" s, speed: aprox. "+StrF(Speed,2)+" MB/s")
  PrintN("Total processed data: "+Str(TotalData)+" bytes ("+Str(TotalData / 1024 / 1024)+") MB")
  PrintN("The test is pretty slow, but it does random data encryption and")
  PrintN("decryption. Still, the algorithm needs some speed improvements :-)")
  PrintN("Ctrl + C to end!")
  PrintN("-------------------------------")

  ;Make a random key
  KeyLen = Random(56, 1)
  *Key = AllocateMemory(KeyLen)
  CryptRandomData(*Key, KeyLen)

  ;Make a buffer with random data
  OriginalLen = Random(#MaxLen, #MinLen)
  *Original = AllocateMemory(OriginalLen)
  CryptRandomData(*Original, OriginalLen)

  ;Make an IV
  *IV = AllocateMemory(8)
  CryptRandomData(*IV, 8)

  ;Do the work
  *EncResult = BlowfishEncoder(*Original, OriginalLen, *Key, KeyLen, *IV, #BF_CBC, #BF_Padding_RFC2630)
  TotalData + *EncResult\OutputLength
  *DecResult = BlowfishDecoder(*EncResult\Output, *EncResult\OutputLength, *Key, KeyLen, *IV, #BF_CBC, #BF_Padding_RFC2630)
  TotalData + *DecResult\OutputLength

  ;Check the work
  If CompareMemory(*Original, *DecResult\Output, OriginalLen) = 1
    Success = 1
  Else
    Success = 0
  EndIf

  ;Write status
  ConsoleLocate(0, 9)
  For Clr = 0 To 4
    PrintN(Space(80))
  Next
  ConsoleLocate(0, 9)
  PrintN("Key: "+BF_PeekHEX(*Key, KeyLen))
  PrintN("IV: "+BF_PeekHEX(*IV, 8))
  PrintN("Encrypted: "+Str(OriginalLen)+" bytes, output size: "+Str(*EncResult\OutputLength)+", code: "+Str(*EncResult\ErrorCode))
  PrintN("Decrypted: "+Str(OriginalLen)+" bytes, output size: "+Str(*DecResult\OutputLength)+", code: "+Str(*DecResult\ErrorCode))
  If Success = 1
    PrintN("Decryption successful!")
  Else
    PrintN("Error at decryption!"):Beep_(1500,500):Input():End
  EndIf
  PrintN("-------------------------------")
  ConsoleLocate(0, 16)
  
  ;Clean up
  FreeMemory(*Key)
  FreeMemory(*Original)
  FreeMemory(*IV)
  FreeMemory(*EncResult\Output)
  FreeMemory(*EncResult)
  FreeMemory(*DecResult\Output)
  FreeMemory(*DecResult)
  
Next

ConsoleLocate(0, 16)
PrintN("All rounds finished. Press Enter to quit.")

Input()

CBCTest.pb

Code: Select all

;[!] Compile as ASCII

;BF include
XIncludeFile "BE_BlowFish.pbi"

Define SourceHex.s, KeyHex.s, IVHex.s, *SourceBuff, *KeyBuff, *IVBuff, SourceBuffLen, KeyBuffLen, IVBuffLen
Define *EncResult.BF_Data, CipherOutTest.s, CipherOutHex.s, *DecResult.BF_Data, UncipherOutHex.s

;Our test vector for encryption. This is what we should get after encryption
CipherOutTest = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D9749DECBEC05D264B"

;These are the source hex strings for our buffers
SourceHex      = "37363534333231204E6F77206973207468652074696D6520666F722000"
KeyHex         = "0123456789ABCDEFF0E1D2C3B4A59687"
IVHex          = "FEDCBA9876543210"

;Allocate the buffers
*SourceBuff    = AllocateMemory(Len(SourceHex))
*KeyBuff       = AllocateMemory(Len(KeyHex))
*IVBuff        = AllocateMemory(Len(IVHex))

;Initialize them with our hex data
SourceBuffLen  = BF_PokeHex(*SourceBuff, @SourceHex, Len(SourceHex))
KeyBuffLen     = BF_PokeHex(*KeyBuff, @KeyHex, Len(KeyHex))
IVBuffLen      = BF_PokeHex(*IVBuff, @IVHex, Len(IVHex))

;Now encrypt and compare the result with the vector
*EncResult = BlowfishEncoder(*SourceBuff, SourceBuffLen, *KeyBuff, KeyBuffLen, *IVBuff, #BF_CBC, #BF_Padding_RFC2630)
If *EncResult\ErrorCode = #BF_Error_OK
  *DecResult = BlowfishDecoder(*EncResult\Output, *EncResult\OutputLength, *KeyBuff, KeyBuffLen, *IVBuff, #BF_CBC, #BF_Padding_RFC2630)
  CipherOutHex = BF_PeekHEX(*EncResult\Output, *EncResult\OutputLength)
  UncipherOutHex = BF_PeekHEX(*DecResult\Output, *DecResult\OutputLength)
  If CipherOutHex = CipherOutTest And UncipherOutHex = SourceHex
    Debug "Cipher-Feedback mode test passed!"
  Else
    Debug "[!] CBC test failed!" : Beep_(1500,500)
  EndIf
  Debug ""
  Debug "Encryption:"
  Debug "Got back: "+CipherOutHex
  Debug "Expected: "+CipherOutTest
  Debug ""
  Debug "Decryption:"
  Debug "Got back: "+UncipherOutHex
  Debug "Expected: "+SourceHex
  ;Free the buffers we got back
  FreeMemory(*EncResult\Output)
  FreeMemory(*DecResult\Output)
Else
  Debug "[!] CBC test failed with error code: "+Str(*EncResult\ErrorCode)
EndIf
;These are always safe to free when calling BlowfishEncoder / BlowfishDecoder
If *EncResult <> 0 : FreeMemory(*EncResult) : EndIf
If *DecResult <> 0 : FreeMemory(*DecResult) : EndIf

ECBTest.pb - Needs the file called "ECB_Vectors.txt", posted below

Code: Select all


;[!] Make sure to have ECB_Vectors.txt in the same directory
;[!] Compile as ASCII

EnableDebugger

;BF include
XIncludeFile "BE_BlowFish.pbi"

;A structure to hold the test vector data
Structure TestVector
  *Key
  *Plain
  PlainString.s
  Expected.s
EndStructure

;The list that contains the vector data
NewList Vectors.TestVector()

Define TestString.s, KeyS.s, PlainS.s, CipherS.s, *Key, *Plain, *Out, *Dec, Good, CTX.BF_Context
Define Status.s, Result.s, ResultDec.s, *Encode.BF_LargeInt, *Decode.BF_LargeInt

;First read the test vectors file. This file contains the official test vectors for ECB mode
If ReadFile(0, "ECB_Vectors.txt")
  Debug "------------"
  Debug "Blowfish for PureBasic"
  Debug "Testing ECB encyption against the test vectors"
  Debug "------------"
  While Not Eof(0)
    TestString = ReadString(0)
    If Left(TestString, 1) <> ";"
      ;Read and convert the data to binary
      KeyS = StringField(TestString,1,"|")
      PlainS = StringField(TestString,2,"|")
      CipherS = StringField(TestString,3,"|")
      *Key = AllocateMemory(8)
      *Plain = AllocateMemory(8)
      BF_PokeHEX(*Key, @KeyS, Len(KeyS))
      BF_PokeHEX(*Plain, @PlainS, Len(PlainS))
      ;Add the data in memory
      AddElement(Vectors())
      Vectors()\Key = *Key
      Vectors()\Plain = *Plain
      Vectors()\PlainString = PlainS
      Vectors()\Expected = CipherS
    EndIf
  Wend
  CloseFile(0)
Else
  Debug "Cannot read Vectors.txt" : End
EndIf

*Encode = AllocateMemory(8)
*Decode = AllocateMemory(8)

;Now let's start the test
ForEach Vectors()
   *Out = AllocateMemory(8)
   *Dec = AllocateMemory(8)
   BF_InitKey(@CTX, Vectors()\Key, 8)
   ;Here's the thing: the official test vectors are all in Big-endian format
   ;so we need to convert them before and after encryption
   CopyMemory(Vectors()\Plain, *Encode, 8)
   *Encode\L[0] = Endian(*Encode\L[0])
   *Encode\L[1] = Endian(*Encode\L[1])
   ;Encrypt the first and second halves: 4 bytes | 4 bytes
   BF_EncBlock(@CTX, @*Encode\L[0], @*Encode\L[1])
   ;Convert back to little endian
   *Encode\L[0] = Endian(*Encode\L[0])
   *Encode\L[1] = Endian(*Encode\L[1])
   CopyMemory(*Encode, *Out, 8)
   ;Same for decryption
   CopyMemory(*Out, *Decode, 8)
   *Decode\L[0] = Endian(*Decode\L[0])
   *Decode\L[1] = Endian(*Decode\L[1])
   ;Decrypt the first and second halves: 4 bytes | 4 bytes
   BF_DecBlock(@CTX, @*Decode\L[0], @*Decode\L[1])
   ;Convert back to little endian
   *Decode\L[0] = Endian(*Decode\L[0])
   *Decode\L[1] = Endian(*Decode\L[1])
   CopyMemory(*Decode, *Dec, 8)
   ;Now read the obtained hex data
   Result = BF_PeekHEX(*Out, 8)
   ResultDec = BF_PeekHEX(*Dec, 8)
   ;Compare and write the result
   If Result = Vectors()\Expected And Vectors()\PlainString = ResultDec
     Status = "[GOOD] "
     Good + 1
   Else
     Status = "[FAIL] "
   EndIf
   Debug Status
   Debug "got back "+Result+" , expected "+Vectors()\Expected
   Debug "original "+Vectors()\PlainString+" , decrypted: "+ResultDec
   Debug "------------"
   ;Clean up
   FillMemory(@CTX, SizeOf(BF_Context))
   FreeMemory(*Out)
   FreeMemory(*Dec)
   FreeMemory(Vectors()\Key)
   FreeMemory(Vectors()\Plain)
   DeleteElement(Vectors())
Next
If Good = 34
  Debug "All vector tests passed ("+Str(Good)+")"
Else
  Debug "WARNING! "+Str(34-Good)+" tests failed!" : Beep_(1500,500)
EndIf
If *Encode <> 0 : FreeMemory(*Encode) : EndIf
If *Decode <> 0 : FreeMemory(*Decode) : EndIf
Debug "------------"

ECB_Vectors.txt - Do not leave any empty lines when copying the contents
;
;Test vectors for Blowfish implementation in PureBasic
;I just took them out of the original file and arranged
;them for easier loading and testing
;
;Originally found here: http://www.schneier.com/code/vectors.txt
;
;Structure: KEYBYTES|PLAINTEXT|CIPHERTEXT (e.g. expected result)
;
0000000000000000|0000000000000000|4EF997456198DD78
FFFFFFFFFFFFFFFF|FFFFFFFFFFFFFFFF|51866FD5B85ECB8A
3000000000000000|1000000000000001|7D856F9A613063F2
1111111111111111|1111111111111111|2466DD878B963C9D
0123456789ABCDEF|1111111111111111|61F9C3802281B096
1111111111111111|0123456789ABCDEF|7D0CC630AFDA1EC7
0000000000000000|0000000000000000|4EF997456198DD78
FEDCBA9876543210|0123456789ABCDEF|0ACEAB0FC6A0A28D
7CA110454A1A6E57|01A1D6D039776742|59C68245EB05282B
0131D9619DC1376E|5CD54CA83DEF57DA|B1B8CC0B250F09A0
07A1133E4A0B2686|0248D43806F67172|1730E5778BEA1DA4
3849674C2602319E|51454B582DDF440A|A25E7856CF2651EB
04B915BA43FEB5B6|42FD443059577FA2|353882B109CE8F1A
0113B970FD34F2CE|059B5E0851CF143A|48F4D0884C379918
0170F175468FB5E6|0756D8E0774761D2|432193B78951FC98
43297FAD38E373FE|762514B829BF486A|13F04154D69D1AE5
07A7137045DA2A16|3BDD119049372802|2EEDDA93FFD39C79
04689104C2FD3B2F|26955F6835AF609A|D887E0393C2DA6E3
37D06BB516CB7546|164D5E404F275232|5F99D04F5B163969
1F08260D1AC2465E|6B056E18759F5CCA|4A057A3B24D3977B
584023641ABA6176|004BD6EF09176062|452031C1E4FADA8E
025816164629B007|480D39006EE762F2|7555AE39F59B87BD
49793EBC79B3258F|437540C8698F3CFA|53C55F9CB49FC019
4FB05E1515AB73A7|072D43A077075292|7A8E7BFA937E89A3
49E95D6D4CA229BF|02FE55778117F12A|CF9C5D7A4986ADB5
018310DC409B26D6|1D9D5C5018F728C2|D1ABB290658BC778
1C587F1C13924FEF|305532286D6F295A|55CB3774D13EF201
0101010101010101|0123456789ABCDEF|FA34EC4847B268B2
1F1F1F1F0E0E0E0E|0123456789ABCDEF|A790795108EA3CAE
E0FEE0FEF1FEF1FE|0123456789ABCDEF|C39E072D9FAC631D
0000000000000000|FFFFFFFFFFFFFFFF|014933E0CDAFF6E4
FFFFFFFFFFFFFFFF|0000000000000000|F21E9A77B71C49BC
0123456789ABCDEF|0000000000000000|245946885754369A
FEDCBA9876543210|FFFFFFFFFFFFFFFF|6B5C5A9C5D9E0A5A
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
idle
Always Here
Always Here
Posts: 5097
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Native Blowfish encryption (x86) (5 Feb 2013)

Post by idle »

Thanks will take a proper look at this later
Windows 11, Manjaro, Raspberry Pi OS
Image
jassing
Addict
Addict
Posts: 1775
Joined: Wed Feb 17, 2010 12:00 am

Re: Native Blowfish encryption (x86) (5 Feb 2013)

Post by jassing »

For mild speed improvements, use #PB_Memory_NoClear in your AllocateMemory() calls.
Post Reply