Browse Source

toBytes fixes

md5 crashing
Marcin Krzyżanowski 11 years ago
parent
commit
faa315738e

+ 4 - 0
CryptoSwift.xcodeproj/project.pbxproj

@@ -13,6 +13,7 @@
 		7547195119931802002FA5F1 /* IntExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7547195019931802002FA5F1 /* IntExtension.swift */; };
 		754BE45B19693E190098E6F3 /* CryptoSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 754BE45A19693E190098E6F3 /* CryptoSwift.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		754BE46819693E190098E6F3 /* CryptoSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754BE46719693E190098E6F3 /* CryptoSwiftTests.swift */; };
+		754C8FED19979F94005AD904 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754C8FEC19979F94005AD904 /* ArrayExtension.swift */; };
 		7552614E1993051E000D2B20 /* CryptoHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7552614D1993051E000D2B20 /* CryptoHash.swift */; };
 		758F3F761992E57D0014BBDA /* Playground in Resources */ = {isa = PBXBuildFile; fileRef = 758F3F751992E57D0014BBDA /* Playground */; };
 		758F3F781992F6CE0014BBDA /* ByteExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758F3F771992F6CE0014BBDA /* ByteExtension.swift */; };
@@ -94,6 +95,7 @@
 		754BE46019693E190098E6F3 /* CryptoSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CryptoSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		754BE46619693E190098E6F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		754BE46719693E190098E6F3 /* CryptoSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoSwiftTests.swift; sourceTree = "<group>"; };
+		754C8FEC19979F94005AD904 /* ArrayExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = "<group>"; };
 		7552614D1993051E000D2B20 /* CryptoHash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CryptoHash.swift; sourceTree = "<group>"; };
 		758F3F751992E57D0014BBDA /* Playground */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Playground; path = CryptoSwift/Playground; sourceTree = "<group>"; };
 		758F3F771992F6CE0014BBDA /* ByteExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ByteExtension.swift; sourceTree = "<group>"; };
@@ -156,6 +158,7 @@
 				758F3F771992F6CE0014BBDA /* ByteExtension.swift */,
 				7547195019931802002FA5F1 /* IntExtension.swift */,
 				752DEF7619693EA000E17557 /* NSDataExtension.swift */,
+				754C8FEC19979F94005AD904 /* ArrayExtension.swift */,
 				754BE45819693E190098E6F3 /* Supporting Files */,
 			);
 			path = CryptoSwift;
@@ -305,6 +308,7 @@
 				7552614E1993051E000D2B20 /* CryptoHash.swift in Sources */,
 				750A54601992D2680017DA75 /* MD5.swift in Sources */,
 				752DEF7719693EA000E17557 /* NSDataExtension.swift in Sources */,
+				754C8FED19979F94005AD904 /* ArrayExtension.swift in Sources */,
 				7547195119931802002FA5F1 /* IntExtension.swift in Sources */,
 				758F3F781992F6CE0014BBDA /* ByteExtension.swift in Sources */,
 			);

+ 26 - 0
CryptoSwift/ArrayExtension.swift

@@ -0,0 +1,26 @@
+//
+//  ArrayExtension.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 10/08/14.
+//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
+//
+
+import Foundation
+
+extension Array {
+    
+    /** split in chunks with given chunk size */
+    internal func chunks(chunksize:Int) -> [Array<T>] {
+        var words:[[T]] = [[T]]()
+        for var idx = chunksize; idx <= self.count; idx = idx + chunksize {
+            let word = Array(self[idx - chunksize..<idx])
+            words.append(word)
+        }
+        let reminder = Array(suffix(self, self.count % chunksize))
+        if (reminder.count > 0) {
+            words.append(reminder)
+        }
+        return words
+    }
+}

+ 15 - 9
CryptoSwift/IntExtension.swift

@@ -10,16 +10,15 @@ import Foundation
 
 extension Int {
     
-    /** Array of bytes (little-endian) */
-    internal func toBytes() -> Array<Byte> {
-        let totalBytes = sizeof(Int)
+    /** Array of bytes with optional padding (little-endian) */
+    public func toBytes(_ totalBytes: Int = sizeof(Int)) -> Array<Byte> {
         var bytes:[Byte] = [Byte](count: totalBytes, repeatedValue: 0)
-
+        
         // first convert to data
         let data = NSData(bytes: [self] as [Int], length: totalBytes)
         
         // then convert back to bytes, byte by byte
-        for i in 0..<data.length {
+        for i in 0..<Swift.min(sizeof(Int),totalBytes) {
             var b:Byte = 0
             data.getBytes(&b, range: NSRange(location: i,length: 1))
             bytes[totalBytes - 1 - i] = b
@@ -28,13 +27,20 @@ extension Int {
     }
     
     /** Int with array bytes (little-endian) */
-    static func withBytes(bytes: Array<Byte>) -> Int {
+    public static func withBytes(bytes: Array<Byte>) -> Int {
         var i:Int = 0
-        let totalBytes = bytes.count > sizeof(Int) ? sizeof(Int) : bytes.count;
+        let totalBytes = Swift.min(bytes.count, sizeof(Int))
         
-        let data = NSData(bytes: bytes, length: totalBytes)
-        data.getBytes(&i, length: totalBytes)
+        // get slice of Int
+        let start = Swift.max(bytes.count - sizeof(Int),0)
+        var intarr = Array<Byte>(bytes[start..<(start + totalBytes)])
+        // extend to Int size if necessary
+        while (intarr.count < sizeof(Int)) {
+            intarr.insert(0 as Byte, atIndex: 0)
+        }
         
+        let data = NSData(bytes: intarr, length: intarr.count)
+        data.getBytes(&i, length: sizeof(Int));
         return i.byteSwapped
     }
 }

+ 188 - 41
CryptoSwift/MD5.swift

@@ -11,13 +11,13 @@ import Foundation
 class MD5 {
 
     /** specifies the per-round shift amounts */
-    let s: [UInt32] = [7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
+    let SHIFT_AMTS: [UInt32] = [7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
                        5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,
                        4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,
                        6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21]
     
     /** binary integer part of the sines of integers (Radians) */
-    let K: [UInt32] = [0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
+    let TABLE_T: [UInt32] = [0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
                        0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,
                        0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,
                        0x6b901122,0xfd987193,0xa679438e,0x49b40821,
@@ -37,11 +37,11 @@ class MD5 {
     /** A */
     var a0: UInt32 = 0x67452301
     /** B */
-    var a1: UInt32 = 0xefcdab89
+    var b0: UInt32 = 0xefcdab89
     /** C */
-    var a2: UInt32 = 0x98badcfe
+    var c0: UInt32 = 0x98badcfe
     /** D */
-    var a3: UInt32 = 0x10325476
+    var d0: UInt32 = 0x10325476
     
     var message: NSData
     
@@ -53,47 +53,194 @@ class MD5 {
     {
         return MD5(message).calculate();
     }
-    
-    func paddedBuffer() -> NSData {
-        var tmpMessage: NSMutableData = NSMutableData(data: message)
-        
-        // Step 1. Append Padding Bits
-        tmpMessage.appendBytes([0x80]) // append one bit to message
+
+    func calculate() -> NSData? {
+        let numBlocks = ((message.length + 8) >> 6) + 1
+        let totalLen = numBlocks << 6
+        var paddingBytes:[Byte] = [Byte](count: totalLen /* - message.length */, repeatedValue: 0)
+        paddingBytes[0] = 0x80
+
+        var messageLenBits = message.length << 3
+        for i in 0..<8 {
+            paddingBytes[paddingBytes.count - 8 + i] = Byte(messageLenBits)
+            messageLenBits >>= 8
+        }
+
+        var a = a0
+        var b = b0
+        var c = c0
+        var d = d0
+        var buffer:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
         
-        // "0" bits are appended
-        while tmpMessage.length % 64 != 56 {
-            tmpMessage.appendBytes([0x00])
+        for i in 0..<numBlocks {
+            
+            var index = i << 6
+            for j in 0..<64 {
+                index++
+                var val:UInt32
+                if (index < message.length) {
+                    val = UInt32(message.arrayOfBytes()[index])
+                } else {
+                    var tmp:UInt32 = UInt32(paddingBytes[index - message.length])
+                    var tmp2 = tmp << 24
+                    val = UInt32(tmp2)
+                    val = val | (buffer[j >> 2] >> 8)
+                }
+                buffer[j >> 2] = val
+            }
+            
+            var originalA:UInt32 = a
+            var originalB:UInt32 = b
+            var originalC:UInt32 = c
+            var originalD:UInt32 = d
+
+            for j in 0...63 {
+                let div16 = j >> 4
+                var f:UInt32 = 0
+                var bufferIndex = j
+                
+                switch (div16) {
+                case 0:
+                    f = (b & c) | (~b & d);
+                    break
+                case 1:
+                    f = (b & d) | (c & ~d);
+                    bufferIndex = (bufferIndex * 5 + 1) & 0x0F;
+                    break;
+                    
+                case 2:
+                    f = b ^ c ^ d;
+                    bufferIndex = (bufferIndex * 3 + 5) & 0x0F;
+                    break;
+                    
+                case 3:
+                    f = c ^ (b | ~d);
+                    bufferIndex = (bufferIndex * 7) & 0x0F;
+                    break;
+                default:
+                    break
+                }
+                
+                var t1 = a + f // + buffer[bufferIndex]
+                var temp = b + rotateLeft(a + f + buffer[bufferIndex] + TABLE_T[j], SHIFT_AMTS[(div16 << 2) | (j & 3)]);
+                a = d;
+                d = c;
+                c = b;
+                b = temp;
+            }
+            a += originalA;
+            b += originalB;
+            c += originalC;
+            d += originalD;
         }
         
-        // Step 2. Append Length
-        let lengthInBits: Int = (message.length * 8)
-        // A 64-bit representation of b
-//        for i in stride(from: 0, through: 56, by: 8) {
-//            let byte = (Byte)(lengthInBits >> i)
-//            tmpMessage.appendBytes([byte])
-//        }
+        println("dalej");
         
-//        let temp: Int = (448 - (message.length * 8) % 512)
-//        var pad: Int = (temp + 512) % 512 // no of bits to be pad
+        return nil
+    }
+
+//    func calculate() -> NSData? {
+//        var tmpMessage: NSMutableData = NSMutableData(data: message)
+//        
+//        // Step 1. Append Padding Bits
+//        tmpMessage.appendBytes([0x80]) // append one bit (Byte with one bit) to message
 //        
-//        if (pad == 0) {
-//            pad = 512
+//        // append "0" bit until message length in bits ≡ 448 (mod 512)
+//        while tmpMessage.length % 64 != 56 {
+//            tmpMessage.appendBytes([0x00])
 //        }
 //        
-//        // buffer size in multiple of bytes
-//        let sizeMsgBuff = message.length + (pad / 8) + 8
-//        // 64 bit size pad
-//        let sizeMsg = message.length * 8
-        
-        var buf: NSMutableData = NSMutableData();
-        return buf.copy() as NSData;
-    }
-    
-    //TODO
-    func calculate() -> NSData?
-    {
-        let paddedData = self.paddedBuffer();
-        return paddedBuffer();
+//        // Step 2. Append Length
+//        let lengthInBits: Int = (message.length * 8)
+//        // A 64-bit representation of lengthInBits
+//        tmpMessage.appendBytes(lengthInBits.toBytes(64 / 8));
+//        
+//        println("tmpMessage \(tmpMessage)")
+//        // Process the message in successive 512-bit chunks:
+//        let chunkSizeBytes = 512 / 8
+//        var leftMessageBytes = tmpMessage.length
+//        for var i = 0; i < tmpMessage.length; i = i + chunkSizeBytes, leftMessageBytes -= chunkSizeBytes {
+//            let chunk = tmpMessage.subdataWithRange(NSRange(location: i, length: min(chunkSizeBytes,leftMessageBytes)))
+//            
+//            // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
+//            var M:[UInt32] = [UInt32]()
+//            for x in 0...15 {
+//                var word:UInt32 = 0;
+//                chunk.getBytes(&word, range: NSRange(location:x * 4, length: sizeof(UInt32)));
+//                M.append(word)
+//            }
+//            
+//            // Initialize hash value for this chunk:
+//            var A:UInt32 = a0
+//            var B:UInt32 = b0
+//            var C:UInt32 = c0
+//            var D:UInt32 = d0
+//            
+//            var dTemp:UInt32
+//            
+//            // Main loop
+//            for i in 0...63 {
+//                var g:Int = 0
+//                var F:UInt32 = 0
+//                
+//                switch (i) {
+//                case 0...15:
+//                    F = (B & C) | ((~B) & D)
+//                    //F = D ^ (B & (C ^ D))
+//                    g = i
+//                    break
+//                case 16...31:
+//                    F = (D & B) | (~D & C)
+//                    g = (5 * i + 1) % 16
+//                    break
+//                case 32...47:
+//                    F = B ^ C ^ D
+//                    g = (3 * i + 5) % 16
+//                    break
+//                case 48...63:
+//                    F = C ^ (B | (~D))
+//                    g = (7 * i) % 16
+//                    break
+//                default:
+//                    break
+//                }
+//                dTemp = D
+//                D = C
+//                C = B
+//                // ZONL A + F + K[i] overflow uint32
+//                B = B + leftrotate((A + F + K[i] + M[g]), amount: s[i])
+//                A = dTemp
+//            }
+//            a0 = a0 + A
+//            b0 = b0 + B
+//            c0 = c0 + C
+//            d0 = d0 + D
+//        }
+//        
+//        var buf: NSMutableData = NSMutableData();
+//        buf.appendBytes(&a0, length: sizeof(UInt32))
+//        buf.appendBytes(&b0, length: sizeof(UInt32))
+//        buf.appendBytes(&c0, length: sizeof(UInt32))
+//        buf.appendBytes(&d0, length: sizeof(UInt32))
+//        return buf.copy() as? NSData;
+//    }
+//    
+//    private func fn32(n:UInt32) -> UInt32 {
+//        var newN:Int = Int(n)
+//        let power2to32 = Int(pow(Double(2),Double(32)))
+//        while newN > 0x7FFFFFFF {
+//            newN -= power2to32
+//        }
+//        while newN < 0x80000000 {
+//            newN += power2to32
+//        }
+//        return UInt32(newN)
+//    }
+//    
+    private func rotateLeft(x:UInt32, _ amount:UInt32) -> UInt32 {
+        let x = 0xFFFFFFFF as UInt32
+        var ret:UInt32 = ((x << amount) | (x >> (32 - amount))) & 0xFFFFFFFF
+        return ret
     }
-    
-}
+}
+

+ 1 - 1
CryptoSwift/Playground/MyPlayground.playground/contents.xcplayground

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<playground version='3.0' sdk='iphonesimulator'>
+<playground version='3.0' sdk='iphonesimulator' auto-termination-delay='20'>
     <sections>
         <code source-file-name='section-1.swift'/>
     </sections>

+ 39 - 58
CryptoSwift/Playground/MyPlayground.playground/section-1.swift

@@ -2,65 +2,46 @@
 
 import UIKit
 
-extension Int {
-    
-    /** Array of bytes (little-endian) */
-    internal func toBytes() -> Array<Byte> {
-        let totalBytes = sizeof(Int)
-        var bytes:[Byte] = [Byte](count: totalBytes, repeatedValue: 0)
-        
-        // first convert to data
-        let data = NSData(bytes: [self] as [Int], length: totalBytes)
-        
-        // then convert back to bytes, byte by byte
-        for i in 0..<data.length {
-            var b:Byte = 0
-            data.getBytes(&b, range: NSRange(location: i,length: 1))
-            bytes[totalBytes - 1 - i] = b
+//var array = [120,9,8,7,6,5,6,7,8,9]
+//
+//var p = Int(pow(Double(2),Double(3)))
+//
+
+// Crash because of overflow
+//var b:Byte = 128
+//var i = b << 24
+
+var b:Byte = 128
+var i = UInt32(b) << 24
+
+//var words:[[Int]] = [[Int]]()
+//for (idx, item) in enumerate(array) {
+//    if (idx > 0) && (idx + 2) <= array.count && (idx % 2) == 0 {
+//        let word = array[idx..<idx + 2]
+//    }
+//}
+
+//for var idx = 2; idx <= array.count; idx = idx + 2 {
+//    let word = Array(array[idx - 2..<idx])
+//    words.append(word)
+//}
+//let reminder = Array(suffix(array, array.count % 2))
+//words.append(reminder)
+//
+//words
+
+extension Array {
+    func chunks(chunksize:Int) -> [Array<T>] {
+        var words:[[T]] = [[T]]()
+        for var idx = chunksize; idx <= self.count; idx = idx + chunksize {
+            let word = Array(self[idx - chunksize..<idx])
+            words.append(word)
         }
-        return bytes
-    }
-    
-    /** Int with array bytes (little-endian) */
-    static func withBytes(bytes: Array<Byte>) -> Int {
-        var i:Int = 0
-        let totalBytes = bytes.count > sizeof(Int) ? sizeof(Int) : bytes.count;
-        
-        let data = NSData(bytes: bytes, length: totalBytes)
-        data.getBytes(&i, length: totalBytes)
-        
-        return i.byteSwapped
+        let reminder = Array(suffix(self, self.count % chunksize))
+        if (reminder.count > 0) {
+            words.append(reminder)
+        }
+        return words
     }
 }
 
-let iii:Int = 1024 //0x5A
-let bytesArray = iii.toBytes()
-let iiiRecover = Int.withBytes(bytesArray)
-
-//var str = "Hello, playground"
-//
-//let string: NSString = "ABCDE"
-//let message: NSData = string.dataUsingEncoding(NSUTF8StringEncoding)
-//
-//var tmpMessage: NSMutableData = NSMutableData(data: message)
-//// append one bit to message
-//let oneBit: [UInt8] = [0x5A] //0x80
-//tmpMessage.appendBytes(oneBit, length: 1)
-//
-//let b:Byte = 3
-//b.bits()
-//
-//let lengthInBits:Int = 257
-//
-//
-//// little endian 7 6 5 4 3 2 1 0
-//// big endin     0 1 2 3 4 5 6 7
-////var step = 0;
-////for i in stride(from: 0, through: 56, by: 8) {
-////    let byte = (Byte)(lengthInBits >> i)
-////    byte.bitsLE()
-////    step = step + 1
-////}
-//
-//
-//let output: NSString = NSString(data: tmpMessage, encoding: NSUTF8StringEncoding)

+ 9 - 0
CryptoSwift/Playground/MyPlayground.playground/timeline.xctimeline

@@ -2,5 +2,14 @@
 <Timeline
    version = "3.0">
    <TimelineItems>
+      <LoggerValueHistoryTimelineItem
+         documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=1125&amp;EndingColumnNumber=6&amp;EndingLineNumber=46&amp;StartingColumnNumber=4&amp;StartingLineNumber=46&amp;Timestamp=429411124.008604">
+      </LoggerValueHistoryTimelineItem>
+      <LoggerValueHistoryTimelineItem
+         documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=1125&amp;EndingColumnNumber=8&amp;EndingLineNumber=46&amp;StartingColumnNumber=4&amp;StartingLineNumber=46&amp;Timestamp=429411124.008604">
+      </LoggerValueHistoryTimelineItem>
+      <LoggerValueHistoryTimelineItem
+         documentLocation = "#CharacterRangeLen=0&amp;CharacterRangeLoc=1125&amp;EndingColumnNumber=95&amp;EndingLineNumber=46&amp;StartingColumnNumber=15&amp;StartingLineNumber=46&amp;Timestamp=429411124.008604">
+      </LoggerValueHistoryTimelineItem>
    </TimelineItems>
 </Timeline>

+ 14 - 1
CryptoSwiftTests/CryptoSwiftTests.swift

@@ -19,10 +19,23 @@ class CryptoSwiftTests: XCTestCase {
         super.tearDown()
     }
     
+    func testIntExtension() {
+        let i1:Int = 1024
+        let i1Array = i1.toBytes(32 / 8) // 32 bit
+        let i1recovered = Int.withBytes(i1Array)
+        
+        XCTAssertEqual(i1, i1recovered, "Bytes conversion failed")
+        
+        let i2:Int = 1024
+        let i2Array = i2.toBytes(160 / 8) // 160 bit
+        let i2recovered = Int.withBytes(i1Array)
+        
+        XCTAssertEqual(i2, i2recovered, "Bytes conversion failed")
+    }
+    
     func testMD5() {
         var data:NSData = NSData(bytes: [49, 50, 51] as [Byte], length: 3)
 //        var data:NSData = NSData(bytes: [49, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 49, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50, 51, 50] as [Byte], length: 40)
-        let zzz = data.md5()?.hexString
         var md5data = data.md5()
         XCTAssertNotNil(md5data, "MD5 calculation failed")