Native Blowfish encryption (x86) (5 Feb 2013)
Posted: Tue Feb 05, 2013 8:39 pm
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:
Examples 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
;-----------------------------------------------------------------------------------