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
;-----------------------------------------------------------------------------------