diff --git a/CLI Harness/App.xojo_code b/CLI Harness/App.xojo_code index 8c0ae9a..ffcba79 100644 --- a/CLI Harness/App.xojo_code +++ b/CLI Harness/App.xojo_code @@ -806,7 +806,7 @@ Inherits ConsoleApplication #tag Constant, Name = kPaddingPKCS, Type = String, Dynamic = False, Default = \"PKCS", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Private + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Private #tag EndConstant diff --git a/CLI Harness/M_Crypto CLI Harness.xojo_project b/CLI Harness/M_Crypto CLI Harness.xojo_project index 3022241..717cebf 100644 --- a/CLI Harness/M_Crypto CLI Harness.xojo_project +++ b/CLI Harness/M_Crypto CLI Harness.xojo_project @@ -29,7 +29,7 @@ Class=DataReader;DataReader.xojo_code;&h00000000333A37FF;&h0000000000000000;fals Class=ScryptUnitTester;../Shared Classes/Scrypt_MTC/ScryptUnitTester.xojo_code;&h000000005461BFFF;&h0000000053BF77FF;false Class=BadInputException;../Shared Classes/Scrypt_MTC/BadInputException.xojo_code;&h0000000028B777FF;&h0000000053BF77FF;false MajorVersion=2 -MinorVersion=3 +MinorVersion=5 SubVersion=1 NonRelease=0 Release=3 diff --git a/Desktop Harness/M_Crypto Harness.xojo_project b/Desktop Harness/M_Crypto Harness.xojo_project index 54037ad..0d2ca17 100644 --- a/Desktop Harness/M_Crypto Harness.xojo_project +++ b/Desktop Harness/M_Crypto Harness.xojo_project @@ -58,7 +58,7 @@ Class=SHA512DigestTest;Tests/SHA512DigestTest.xojo_code;&h000000004DB86FFF;&h000 AppMenuBar=MenuBar1 MajorVersion=2 MinorVersion=5 -SubVersion=0 +SubVersion=1 NonRelease=0 Release=3 InfoVersion= diff --git a/Desktop Harness/SHA256Digest_MTC.xojo_code b/Desktop Harness/SHA256Digest_MTC.xojo_code index c458043..6be754f 100644 --- a/Desktop Harness/SHA256Digest_MTC.xojo_code +++ b/Desktop Harness/SHA256Digest_MTC.xojo_code @@ -14,18 +14,22 @@ Protected Class SHA256Digest_MTC #tag Method, Flags = &h0 Sub Process(data As String) - data = Buffer + data - Buffer = "" + if Buffer <> "" then + data = Buffer + data + Buffer = "" + end if - dim remainder as integer = data.LenB mod kChunkBytes + dim dataLen as integer = data.LenB + dim remainder as integer = dataLen mod kChunkBytes if remainder <> 0 then Buffer = data.RightB( remainder ) - data = data.LeftB( data.LenB - buffer.LenB ) + dataLen = dataLen - remainder + data = data.LeftB( dataLen ) end if if data <> "" then Process data, Registers, false - CombinedLength = CombinedLength + data.LenB + CombinedLength = CombinedLength + dataLen end if End Sub @@ -44,6 +48,7 @@ Protected Class SHA256Digest_MTC const k3 as UInt32 = 2 ^ 3 const k6 as UInt32 = 2 ^ 6 const k7 as UInt32 = 2 ^ 7 + const k8 as UInt32 = 2 ^ 8 const k10 as UInt32 = 2 ^ 10 const k11 as UInt32 = 2 ^ 11 const k13 as UInt32 = 2 ^ 13 @@ -54,6 +59,7 @@ Protected Class SHA256Digest_MTC const k19 as UInt32 = 2 ^ 19 const k21 as UInt32 = 2 ^ 21 const k22 as UInt32 = 2 ^ 22 + const k24 as UInt32 = 2 ^ 24 const k25 as UInt32 = 2 ^ 25 const k26 as UInt32 = 2 ^ 26 const k30 as UInt32 = 2 ^ 30 @@ -86,9 +92,13 @@ Protected Class SHA256Digest_MTC if Message is nil then Message = new MemoryBlock( k.Size ) - Message.LittleEndian = false + IsLittleEndian = Message.LittleEndian end if + dim w as MemoryBlock = Message // Convenience + dim p as ptr = Message + dim lastMessageByteIndex as integer = w.Size - 1 + dim dataLen as integer = data.LenB dim mbIn as MemoryBlock @@ -126,7 +136,6 @@ Protected Class SHA256Digest_MTC else // Not isFinal so the data will already be a multiple mbIn = data - mbIn.LittleEndian = false end if @@ -140,33 +149,61 @@ Protected Class SHA256Digest_MTC dim h7 as UInt32 = useRegisters.H7 dim a, b, c, d, e, f, g, h as UInt32 + dim word0, word1, word9, word14 as UInt32 + dim temp1, temp2, maj, ch as UInt32 + dim s0, s1 as UInt32 + dim newValue as UInt32 + static lastRoundIndex as integer = ( k.Size \ 4 ) - 1 dim lastByteIndex as integer = mbIn.Size - 1 - for chunkIndex as integer = 0 to lastByteIndex step kChunkBytes // Split into blocks - dim w as MemoryBlock = Message // Convenience + + // + // If the natural state is LittleEndian, we have + // to flip the bytes around in the data so + // we can use Ptr below. + // + // Unbelievably, this is faster than using the + // MemoryBlock functions to access the data. + // + if IsLittleEndian then + dim pIn as ptr = mbIn + for i as integer = 0 to lastByteIndex step 4 + temp1 = pIn.UInt32( i ) + temp2 = _ + ( temp1 \ k24 ) or _ + ( ( temp1 and &h00FF0000 ) \ k8 ) or _ + ( ( temp1 and &h0000FF00 ) * k8 ) or _ + ( temp1 * k24 ) + if temp2 <> temp1 then + pIn.UInt32( i ) = temp2 + end if + next + end if + + for chunkIndex as integer = 0 to lastByteIndex step kChunkBytes // Split into blocks w.StringValue( 0, kChunkBytes ) = mbIn.StringValue( chunkIndex, kChunkBytes ) - dim lastMessageByteIndex as integer = w.Size - 1 for wordIndex as integer = kChunkBytes to lastMessageByteIndex step 4 - dim word0 as UInt32 = w.UInt32Value( wordIndex - 64 ) - dim word1 as UInt32 = w.UInt32Value( wordIndex - 60 ) - dim word9 as UInt32 = w.UInt32Value( wordIndex - 28 ) - dim word14 as UInt32 = w.UInt32Value( wordIndex - 8 ) + word0 = p.UInt32( wordIndex - 64 ) + word1 = p.UInt32( wordIndex - 60 ) + word9 = p.UInt32( wordIndex - 28 ) + word14 = p.UInt32( wordIndex - 8 ) 'dim s0 as UInt32 = ( RotateRight( word1, 7 ) xor RotateRight( word1, 18 ) ) xor ( word1 \ k3 ) - dim s0 as UInt32 = _ + s0 = _ ( ( ( word1 \ k7 ) or ( word1 * k25 ) ) xor _ ( ( word1 \ k18 ) or ( word1 * k14 ) ) ) _ xor ( word1 \ k3 ) 'dim s1 as UInt32 = ( RotateRight( word14, 17 ) xor RotateRight( word14, 19 ) ) xor ( word14 \ k10 ) - dim s1 as UInt32 = _ + s1 = _ ( ( ( word14 \ k17 ) or ( word14 * k15 ) ) xor _ ( ( word14 \ k19 ) or ( word14 * k13 ) ) ) _ xor ( word14 \ k10 ) - w.UInt32Value( wordIndex ) = word0 + s0 + word9 + s1 + newValue = word0 + s0 + word9 + s1 + p.UInt32( wordIndex ) = newValue next a = h0 @@ -178,25 +215,24 @@ Protected Class SHA256Digest_MTC g = h6 h = h7 - dim lastRoundIndex as integer = ( k.Size \ 4 ) - 1 for i as integer = 0 to lastRoundIndex 'dim s1 as UInt32 = RotateRight( e, 6 ) xor RotateRight( e, 11 ) xor RotateRight( e, 25 ) - dim s1 as UInt32 = _ + s1 = _ ( ( e \ k6 ) or ( e * k26 ) ) xor _ ( ( e \ k11 ) or ( e * k21 ) ) xor _ ( ( e \ k25 ) or ( e * k7 ) ) - dim ch as UInt32 = ( e and f ) xor ( ( not e ) and g ) - dim temp1 as UInt32 = h + s1 + ch + kPtr.UInt32( i * 4 ) + w.UInt32Value( i * 4 ) + ch = ( e and f ) xor ( ( not e ) and g ) + temp1 = h + s1 + ch + kPtr.UInt32( i * 4 ) + p.UInt32( i * 4 ) 'dim s0 as UInt32 = RotateRight( a, 2 ) xor RotateRight( a, 13 ) xor RotateRight( a, 22 ) - dim s0 as UInt32 = _ + s0 = _ ( ( a \ k2 ) or ( a * k30 ) ) xor _ ( ( a \ k13 ) or ( a * k19 ) ) xor _ ( ( a \ k22 ) or ( a * k10 ) ) - dim maj as UInt32 = ( a and b ) xor ( a and c ) xor ( b and c ) - dim temp2 as UInt32 = s0 + maj + maj = ( a and b ) xor ( a and c ) xor ( b and c ) + temp2 = s0 + maj h = g g = f @@ -258,6 +294,10 @@ Protected Class SHA256Digest_MTC Private CombinedLength As Integer #tag EndProperty + #tag Property, Flags = &h21 + Private IsLittleEndian As Boolean + #tag EndProperty + #tag Property, Flags = &h21 Private Message As MemoryBlock #tag EndProperty @@ -282,7 +322,7 @@ Protected Class SHA256Digest_MTC #tag Constant, Name = kChunkBytes, Type = Double, Dynamic = False, Default = \"64", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Public + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Public #tag EndConstant diff --git a/Desktop Harness/SHA512Digest_MTC.xojo_code b/Desktop Harness/SHA512Digest_MTC.xojo_code index 846c56d..afbedeb 100644 --- a/Desktop Harness/SHA512Digest_MTC.xojo_code +++ b/Desktop Harness/SHA512Digest_MTC.xojo_code @@ -15,18 +15,22 @@ Protected Class SHA512Digest_MTC #tag Method, Flags = &h0 Sub Process(data As String) - data = Buffer + data - Buffer = "" + if Buffer <> "" then + data = Buffer + data + Buffer = "" + end if - dim remainder as integer = data.LenB mod kChunkBytes + dim dataLen as integer = data.LenB + dim remainder as integer = dataLen mod kChunkBytes if remainder <> 0 then Buffer = data.RightB( remainder ) - data = data.LeftB( data.LenB - buffer.LenB ) + dataLen = dataLen - remainder + data = data.LeftB( dataLen ) end if if data <> "" then Process data, Registers, false - CombinedLength = CombinedLength + data.LenB + CombinedLength = CombinedLength + dataLen end if End Sub @@ -50,12 +54,14 @@ Protected Class SHA512Digest_MTC const k18 as UInt64 = 2 ^ 18 const k19 as UInt64 = 2 ^ 19 const k23 as UInt64 = 2 ^ 23 + const k24 as UInt64 = 2 ^ 24 const k25 as UInt64 = 2 ^ 25 const k28 as UInt64 = 2 ^ 28 const k30 as UInt64 = 2 ^ 30 const k34 as UInt64 = 2 ^ 34 const k36 as UInt64 = 2 ^ 36 const k39 as UInt64 = 2 ^ 39 + const k40 as UInt64 = 2 ^ 40 const k41 as UInt64 = 2 ^ 41 const k45 as UInt64 = 2 ^ 45 const k46 as UInt64 = 2 ^ 46 @@ -100,18 +106,26 @@ Protected Class SHA512Digest_MTC if Message is nil then Message = new MemoryBlock( k.Size ) - Message.LittleEndian = false + IsLittleEndian = Message.LittleEndian end if + dim w as MemoryBlock = Message // Convenience + dim p as ptr = Message + dim lastMessageByteIndex as integer = w.Size - 1 + dim dataLen as integer = data.LenB dim mbIn as MemoryBlock if isFinal then + // // Add one char to the length + // dim padding as integer = kChunkBytes - ( ( dataLen + 1 ) mod kChunkBytes ) + // // Check if we have enough room for inserting the length + // if padding < 16 then padding = padding + kChunkBytes end if @@ -136,7 +150,6 @@ Protected Class SHA512Digest_MTC else // Not isFinal so the data will already be a multiple mbIn = data - mbIn.LittleEndian = false end if @@ -150,33 +163,65 @@ Protected Class SHA512Digest_MTC dim h7 as UInt64 = useRegisters.H7 dim a, b, c, d, e, f, g, h as UInt64 + dim word0, word1, word9, word14 as UInt64 + dim temp1, temp2, maj, ch as UInt64 + dim s0, s1 as UInt64 + dim newValue as UInt64 + static lastRoundIndex as integer = ( k.Size \ 8 ) - 1 dim lastByteIndex as integer = mbIn.Size - 1 - for chunkIndex as integer = 0 to lastByteIndex step kChunkBytes // Split into blocks - dim w as MemoryBlock = Message // Convenience + + // + // If the natural state is LittleEndian, we have + // to flip the bytes around in the data so + // we can use Ptr below. + // + // Unbelievably, this is faster than using the + // MemoryBlock functions to access the data. + // + if IsLittleEndian then + dim pIn as ptr = mbIn + for i as integer = 0 to lastByteIndex step 8 + temp1 = pIn.UInt64( i ) + temp2 = _ + ( temp1 \ k56 ) or _ + ( ( temp1 and &h00FF000000000000 ) \ k40 ) or _ + ( ( temp1 and &h0000FF0000000000 ) \ k24 ) or _ + ( ( temp1 and &h000000FF00000000 ) \ k8 ) or _ + ( ( temp1 and &h00000000FF000000 ) * k8 ) or _ + ( ( temp1 and &h0000000000FF0000 ) * k24 ) or _ + ( ( temp1 and &h000000000000FF00 ) * k40 ) or _ + ( temp1 * k56 ) + if temp2 <> temp1 then + pIn.UInt64( i ) = temp2 + end if + next + end if + + for chunkIndex as integer = 0 to lastByteIndex step kChunkBytes // Split into blocks w.StringValue( 0, kChunkBytes ) = mbIn.StringValue( chunkIndex, kChunkBytes ) - dim lastMessageByteIndex as integer = w.Size - 1 for wordIndex as integer = kChunkBytes to lastMessageByteIndex step 8 - dim word0 as UInt64 = w.UInt64Value( wordIndex - 128 ) - dim word1 as UInt64 = w.UInt64Value( wordIndex - 120 ) - dim word9 as UInt64 = w.UInt64Value( wordIndex - 56 ) - dim word14 as UInt64 = w.UInt64Value( wordIndex - 16 ) + word0 = p.UInt64( wordIndex - 128 ) + word1 = p.UInt64( wordIndex - 120 ) + word9 = p.UInt64( wordIndex - 56 ) + word14 = p.UInt64( wordIndex - 16 ) 'dim s0 as UInt64 = ( RotateRight( word1, 1 ) xor RotateRight( word1, 8 ) ) xor ( word1 \ k7 ) - dim s0 as UInt64 = _ + s0 = _ ( ( ( word1 \ k1 ) or ( word1 * k63 ) ) xor _ ( ( word1 \ k8 ) or ( word1 * k56 ) ) ) _ xor ( word1 \ k7 ) 'dim s1 as UInt64 = ( RotateRight( word14, 19 ) xor RotateRight( word14, 61 ) ) xor ( word14 \ k6 ) - dim s1 as UInt64 = _ + s1 = _ ( ( ( word14 \ k19 ) or ( word14 * k45 ) ) xor _ ( ( word14 \ k61 ) or ( word14 * k3 ) ) ) _ xor ( word14 \ k6 ) - w.UInt64Value( wordIndex ) = word0 + s0 + word9 + s1 + newValue = word0 + s0 + word9 + s1 + p.UInt64( wordIndex ) = word0 + s0 + word9 + s1 next a = h0 @@ -188,24 +233,23 @@ Protected Class SHA512Digest_MTC g = h6 h = h7 - dim lastRoundIndex as integer = ( k.Size \ 8 ) - 1 for i as integer = 0 to lastRoundIndex 'dim s1 as UInt64 = RotateRight( e, 14 ) xor RotateRight( e, 18 ) xor RotateRight( e, 41 ) - dim s1 as UInt64 = _ + s1 = _ ( ( e \ k14 ) or ( e * k50 ) ) xor _ ( ( e \ k18 ) or ( e * k46 ) ) xor _ ( ( e \ k41 ) or ( e * k23 ) ) - dim ch as UInt64 = ( e and f ) xor ( ( not e ) and g ) - dim temp1 as UInt64 = h + s1 + ch + kPtr.UInt64( i * 8 ) + w.UInt64Value( i * 8 ) + ch = ( e and f ) xor ( ( not e ) and g ) + temp1 = h + s1 + ch + kPtr.UInt64( i * 8 ) + p.UInt64( i * 8 ) 'dim s0 as UInt64 = RotateRight( a, 28 ) xor RotateRight( a, 34 ) xor RotateRight( a, 39 ) - dim s0 as UInt64 = _ + s0 = _ ( ( a \ k28 ) or ( a * k36 ) ) xor _ ( ( a \ k34 ) or ( a * k30 ) ) xor _ ( ( a \ k39 ) or ( a * k25 ) ) - dim maj as UInt64 = ( a and b ) xor ( a and c ) xor ( b and c ) - dim temp2 as UInt64 = s0 + maj + maj = ( a and b ) xor ( a and c ) xor ( b and c ) + temp2 = s0 + maj h = g g = f @@ -267,6 +311,10 @@ Protected Class SHA512Digest_MTC Private CombinedLength As Integer #tag EndProperty + #tag Property, Flags = &h21 + Private IsLittleEndian As Boolean + #tag EndProperty + #tag Property, Flags = &h21 Private Message As MemoryBlock #tag EndProperty @@ -291,7 +339,7 @@ Protected Class SHA512Digest_MTC #tag Constant, Name = kChunkBytes, Type = Double, Dynamic = False, Default = \"128", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Public + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Public #tag EndConstant diff --git a/README.md b/README.md index c56c3c2..ba7eee0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # M_Crypto for Xojo -An encryption library for Xojo that implements Blowfish and AES encryption and Bcrypt hash module, translated from C libraries (included as Xcode projects). +An encryption library for Xojo that implements Blowfish, AES, Bcrypt, Scrypt, SHA-256 digest, and SHA-512 digest. ## Table of Contents @@ -329,6 +329,10 @@ This project was created by and is maintained by Kem Tekinay (ktekinay at mactec ## Release Notes +__2.5.1__ (Nov. 16, 2018) + +- Optimizations to the SHA digest classes making them roughly 10x faster. + __2.5__ (Nov. 15, 2018) - Added `SHA256Digest_MTC` and `SHA512Digest_MTC` classes. diff --git a/Shared Classes/Bcrypt_MTC.xojo_code b/Shared Classes/Bcrypt_MTC.xojo_code index e29a1e0..335c14e 100644 --- a/Shared Classes/Bcrypt_MTC.xojo_code +++ b/Shared Classes/Bcrypt_MTC.xojo_code @@ -379,7 +379,7 @@ Protected Module Bcrypt_MTC #tag Constant, Name = BCRYPT_VERSION, Type = String, Dynamic = False, Default = \"2", Scope = Protected #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Protected + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Protected #tag EndConstant diff --git a/Shared Classes/M_Crypto.xojo_code b/Shared Classes/M_Crypto.xojo_code index 377b244..e2462f3 100644 --- a/Shared Classes/M_Crypto.xojo_code +++ b/Shared Classes/M_Crypto.xojo_code @@ -238,7 +238,7 @@ Protected Module M_Crypto #tag Constant, Name = kRxEncryptCode, Type = String, Dynamic = False, Default = \"(\?x)\n\\A\n(\?|\n (aes) (\?:-\?(\?:(128|192|256)))\?\n | (bf) \n | (blowfish)\n)\n\\b \n(\?:-(cbc|ecb))\?\n\\z", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Protected + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Protected #tag EndConstant diff --git a/Shared Classes/M_Crypto/AES_MTC.xojo_code b/Shared Classes/M_Crypto/AES_MTC.xojo_code index 0af98eb..63fb647 100644 --- a/Shared Classes/M_Crypto/AES_MTC.xojo_code +++ b/Shared Classes/M_Crypto/AES_MTC.xojo_code @@ -1116,7 +1116,7 @@ Inherits M_Crypto.Encrypter #tag Constant, Name = kNb, Type = Double, Dynamic = False, Default = \"4", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Public + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Public #tag EndConstant diff --git a/Shared Classes/M_Crypto/Blowfish_MTC.xojo_code b/Shared Classes/M_Crypto/Blowfish_MTC.xojo_code index 8e6ada8..11742ec 100644 --- a/Shared Classes/M_Crypto/Blowfish_MTC.xojo_code +++ b/Shared Classes/M_Crypto/Blowfish_MTC.xojo_code @@ -1023,7 +1023,7 @@ Implements BcryptInterface #tag Constant, Name = BLF_N, Type = Double, Dynamic = False, Default = \"16", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Public + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Public #tag EndConstant diff --git a/Shared Classes/Scrypt_MTC.xojo_code b/Shared Classes/Scrypt_MTC.xojo_code index 2e8530e..9e616d0 100644 --- a/Shared Classes/Scrypt_MTC.xojo_code +++ b/Shared Classes/Scrypt_MTC.xojo_code @@ -395,7 +395,7 @@ Protected Module Scrypt_MTC #tag Constant, Name = kBlockSize, Type = Double, Dynamic = False, Default = \"64", Scope = Private #tag EndConstant - #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5", Scope = Protected + #tag Constant, Name = kVersion, Type = String, Dynamic = False, Default = \"2.5.1", Scope = Protected #tag EndConstant