Browse Source

truncated shift left &<<

Marcin Krzyżanowski 11 years ago
parent
commit
8439710b1f

+ 12 - 2
CryptoSwift/ByteExtension.swift

@@ -11,7 +11,7 @@ import Foundation
 extension Byte {
     
     /** array of bits */
-    internal func bits() -> Array<Bool> {
+    internal func bits() -> [Bool] {
         let totalBitsCount = sizeof(Byte) * 8
         
         var bitsArray:[Bool] = [Bool](count: totalBitsCount, repeatedValue: false)
@@ -21,9 +21,19 @@ extension Byte {
             let check = self & bitVal
             
             if (check != 0) {
-                bitsArray[j] = 1;
+                bitsArray[j] = true;
             }
         }
         return bitsArray
     }
+    
+    internal func bits() -> String {
+        var s = String()
+        let arr:[Bool] = self.bits()
+        for (idx,b) in enumerate(arr) {
+            s += (b ? "1" : "0")
+            if ((idx + 1) % 8 == 0) { s += " " }
+        }
+        return s
+    }
 }

+ 123 - 5
CryptoSwift/IntExtension.swift

@@ -2,16 +2,49 @@
 //  IntExtension.swift
 //  CryptoSwift
 //
-//  Created by Marcin Krzyzanowski on 07/08/14.
-//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
+//  Created by Marcin Krzyzanowski on 12/08/14.
+//  Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
+//  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:
+//
+//  - 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 is required.
+//  - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+//  - This notice may not be removed or altered from any source or binary distribution.
+
+/*
+    Bit shifting with overflow protection using overflow operator "&".
+    Approach is consistent with standard overflow operators &+,&-,&*,&/
+
+    Note: Works with unsigned integers values only
+
+    Usage
+
+    var i = 1       // init
+    var j = i &<< 2 //shift left
+    j &<<= 2        //shift left and assign
+*/
 
 import Foundation
 
 extension Int {
     
+    private init(bits: [Bool]) {
+        var bitPattern:UInt = 0
+        for (idx,b) in enumerate(bits) {
+            if (b == true) {
+                let bit:UInt = UInt(1) << UInt(idx)
+                bitPattern = bitPattern | bit
+            }
+        }
+        
+        self.init(bitPattern: bitPattern)
+    }
+    
     /** Array of bytes with optional padding (little-endian) */
-    public func toBytes(_ totalBytes: Int = sizeof(Int)) -> Array<Byte> {
+    public func bytes(_ totalBytes: Int = sizeof(Int)) -> [Byte] {
         var bytes:[Byte] = [Byte](count: totalBytes, repeatedValue: 0)
         
         // first convert to data
@@ -25,15 +58,16 @@ extension Int {
         }
         return bytes
     }
-    
+
     /** Int with array bytes (little-endian) */
-    public static func withBytes(bytes: Array<Byte>) -> Int {
+    public static func withBytes(bytes: [Byte]) -> Int {
         var i:Int = 0
         let totalBytes = Swift.min(bytes.count, sizeof(Int))
         
         // 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)
@@ -43,4 +77,88 @@ extension Int {
         data.getBytes(&i, length: sizeof(Int));
         return i.byteSwapped
     }
+    
+    /** Shift bits to the left. All bits are shifted (including sign bit) */
+    private mutating func shiftLeft(count: Int) -> Int {
+        let bitsCount = sizeof(Int) * 8
+        let shiftCount = Swift.min(count, bitsCount - 1)
+        var shiftedValue:Int = 0;
+        
+        for bitIdx in 0..<bitsCount {
+            // if bit is set then copy to result and shift left 1
+            let bit = 1 << bitIdx
+            if ((self & bit) == bit) {
+                shiftedValue = shiftedValue | (bit << shiftCount)
+            }
+        }
+        self = shiftedValue
+        return self
+    }
+    
+    /** Shift bits to the right. All bits are shifted (including sign bit) */
+    private mutating func shiftRight(count: Int) -> Int {
+        let bitsCount = sizeof(Int) * 8
+        let maxBitsForValue = Int(floor(log2(Double(self)) + 1))
+        let shiftCount = Swift.min(count, maxBitsForValue)
+        var shiftedValue:Int = 0;
+        
+        for bitIdx in 0..<bitsCount {
+            // if bit is set then copy to result and shift left 1
+            let bit = 1 << bitIdx
+            if ((self & bit) == bit) {
+                shiftedValue = shiftedValue | (bit >> shiftCount)
+            }
+        }
+        self = Int(shiftedValue)
+        return self
+    }
+}
+
+// Left operator
+
+infix operator &<<= {
+    associativity none
+    precedence 160
+}
+
+
+/** shift left and assign with bits truncation */
+func &<<= (inout lhs: Int, rhs: Int) {
+    lhs.shiftLeft(rhs)
+}
+
+infix operator &<< {
+    associativity none
+    precedence 160
+}
+
+/** shift left with bits truncation */
+func &<< (lhs: Int, rhs: Int) -> Int {
+    var l = lhs;
+    l.shiftLeft(rhs)
+    return l
+}
+
+// Right operator
+
+infix operator &>>= {
+    associativity none
+    precedence 160
+}
+
+/** shift right and assign with bits truncation */
+func &>>= (inout lhs: Int, rhs: Int) {
+    lhs.shiftRight(rhs)
+}
+
+infix operator &>> {
+associativity none
+precedence 160
+}
+
+/** shift right and assign with bits truncation */
+func &>> (lhs: Int, rhs: Int) -> Int {
+    var l = lhs;
+    l.shiftRight(rhs)
+    return l
 }

+ 35 - 15
CryptoSwift/MD5.swift

@@ -73,20 +73,18 @@ class MD5 {
         var buffer:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
         
         for i in 0..<numBlocks {
-            
+            NSLog("BLOCK")
             var index = i << 6
-            for j in 0..<64 {
-                index++
+            for var j = 0; j < 64; j++ {
                 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)
+                    val = UInt32(paddingBytes[index - message.length])
                 }
+                val = (val << 24) | (buffer[j >> 2] >> 8)
                 buffer[j >> 2] = val
+                index++
             }
             
             var originalA:UInt32 = a
@@ -101,7 +99,7 @@ class MD5 {
                 
                 switch (div16) {
                 case 0:
-                    f = (b & c) | (~b & d);
+                    f = ((b) & (c)) | ((~b) & (d));
                     break
                 case 1:
                     f = (b & d) | (c & ~d);
@@ -121,23 +119,45 @@ class MD5 {
                     break
                 }
                 
-                var t1 = a + f // + buffer[bufferIndex]
-                var temp = b + rotateLeft(a + f + buffer[bufferIndex] + TABLE_T[j], SHIFT_AMTS[(div16 << 2) | (j & 3)]);
+                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;
+            a = a &+ originalA;
+            b = b &+ originalB;
+            c = c &+ originalC;
+            d = d &+ originalD;
         }
         
         println("dalej");
         
+        var md5:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
+        var count = 0;
+        for var i = 0; i < 4; i++
+        {
+            var n = (i == 0) ? a : ((i == 1) ? b : ((i == 2) ? c : d));
+            for var j = 0; j < 4; j++
+            {
+                md5.append(n)
+                n >>= 8;
+            }
+        }
+        
+        NSLog("\(toHexString(md5))")
+        
         return nil
     }
+    
+    func toHexString(b:[UInt32]) -> String {
+        var s:String = String()
+        for var i = 0; i < b.count; i++
+        {
+            s = s + String(format: "%02X", arguments: [b[i] & 0xFF])
+        }
+        return s
+    }
 
 //    func calculate() -> NSData? {
 //        var tmpMessage: NSMutableData = NSMutableData(data: message)
@@ -153,7 +173,7 @@ class MD5 {
 //        // Step 2. Append Length
 //        let lengthInBits: Int = (message.length * 8)
 //        // A 64-bit representation of lengthInBits
-//        tmpMessage.appendBytes(lengthInBits.toBytes(64 / 8));
+//        tmpMessage.appendBytes(lengthInBits.bytes(64 / 8));
 //        
 //        println("tmpMessage \(tmpMessage)")
 //        // Process the message in successive 512-bit chunks:

+ 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' auto-termination-delay='20'>
+<playground version='3.0' sdk='iphonesimulator'>
     <sections>
         <code source-file-name='section-1.swift'/>
     </sections>

+ 151 - 38
CryptoSwift/Playground/MyPlayground.playground/section-1.swift

@@ -2,46 +2,159 @@
 
 import UIKit
 
-//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)
+extension Int {
+    
+    private init(bits: [Bool]) {
+        var bitPattern:UInt = 0
+        for (idx,b) in enumerate(bits) {
+            if (b == true) {
+                let bit:UInt = UInt(1) << UInt(idx)
+                bitPattern = bitPattern | bit
+            }
+        }
+        
+        self.init(bitPattern: bitPattern)
+    }
+    
+    /** Array of bytes with optional padding (little-endian) */
+    public func bytes(_ totalBytes: Int = sizeof(Int)) -> [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..<Swift.min(sizeof(Int),totalBytes) {
+            var b:Byte = 0
+            data.getBytes(&b, range: NSRange(location: i,length: 1))
+            bytes[totalBytes - 1 - i] = b
+        }
+        return bytes
+    }
+    
+    /** Int with array bytes (little-endian) */
+    public static func withBytes(bytes: [Byte]) -> Int {
+        var i:Int = 0
+        let totalBytes = Swift.min(bytes.count, sizeof(Int))
+        
+        // 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
+    }
+    
+    /** Shift bits to the left. All bits are shifted (including sign bit) */
+    private mutating func shiftLeft(count: Int) -> Int {
+        let bitsCount = sizeof(Int) * 8
+        let shiftCount = Swift.min(count, bitsCount - 1)
+        var shiftedValue:Int = 0;
+        
+        for bitIdx in 0..<bitsCount {
+            // if bit is set then copy to result and shift left 1
+            let bit = 1 << bitIdx
+            if ((self & bit) == bit) {
+                shiftedValue = shiftedValue | (bit << shiftCount)
+            }
         }
-        let reminder = Array(suffix(self, self.count % chunksize))
-        if (reminder.count > 0) {
-            words.append(reminder)
+        self = shiftedValue
+        return self
+    }
+    
+    /** Shift bits to the right. All bits are shifted (including sign bit) */
+    private mutating func shiftRight(count: Int) -> Int {
+        let bitsCount = sizeof(Int) * 8
+        let maxBitsForValue = Int(floor(log2(Double(self)) + 1))
+        let shiftCount = Swift.min(count, maxBitsForValue)
+        var shiftedValue:Int = 0;
+        
+        for bitIdx in 0..<bitsCount {
+            // if bit is set then copy to result and shift left 1
+            let bit = 1 << bitIdx
+            if ((self & bit) == bit) {
+                shiftedValue = shiftedValue | (bit >> shiftCount)
+            }
         }
-        return words
+        
+        self = Int(shiftedValue)
+        return self
     }
 }
 
+// Left operator
+
+infix operator &<<= {
+associativity none
+precedence 160
+}
+
+
+/** shift left and assign with bits truncation */
+func &<<= (inout lhs: Int, rhs: Int) {
+    lhs.shiftLeft(rhs)
+}
+
+infix operator &<< {
+associativity none
+precedence 160
+}
+
+/** shift left with bits truncation */
+func &<< (lhs: Int, rhs: Int) -> Int {
+    var l = lhs;
+    l.shiftLeft(rhs)
+    return l
+}
+
+// Right operator
+
+infix operator &>>= {
+associativity none
+precedence 160
+}
+
+/** shift right and assign with bits truncation */
+func &>>= (inout lhs: Int, rhs: Int) {
+    lhs.shiftRight(rhs)
+}
+
+infix operator &>> {
+associativity none
+precedence 160
+}
+
+/** shift right and assign with bits truncation */
+func &>> (lhs: Int, rhs: Int) -> Int {
+    var l = lhs;
+    l.shiftRight(rhs)
+    return l
+}
+
+
+var four:Byte = 128
+var shifted = four << 24
+
+//let four:Int = 0b00000100
+//let shifted:Int = four &<< 64
+
+shifted
+
+//var i:Int = 9223372036854775808
+//
+//var i:Int = 9
+//var shifted1 = i &<< 61 //  i &<<= 61
+
+//
+//var i:UInt = UInt(4) << UInt(61)
+
+
+//var i = 9
+//i &<< 8
+//

+ 1 - 7
CryptoSwift/Playground/MyPlayground.playground/timeline.xctimeline

@@ -3,13 +3,7 @@
    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">
+         documentLocation = "file:///Users/marcinkrzyzanowski/Devel/CryptoSwift/CryptoSwift/Playground/MyPlayground.playground#CharacterRangeLen=0&amp;CharacterRangeLoc=3749&amp;EndingLineNumber=3&amp;StartingLineNumber=3&amp;Timestamp=429576064.468724">
       </LoggerValueHistoryTimelineItem>
    </TimelineItems>
 </Timeline>

+ 7 - 2
CryptoSwiftTests/CryptoSwiftTests.swift

@@ -19,15 +19,20 @@ class CryptoSwiftTests: XCTestCase {
         super.tearDown()
     }
     
+    func testOverflow() {
+        var b:Byte = 128
+        var shifted = (Byte)(b << 24)
+    }
+    
     func testIntExtension() {
         let i1:Int = 1024
-        let i1Array = i1.toBytes(32 / 8) // 32 bit
+        let i1Array = i1.bytes(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 i2Array = i2.bytes(160 / 8) // 160 bit
         let i2recovered = Int.withBytes(i1Array)
         
         XCTAssertEqual(i2, i2recovered, "Bytes conversion failed")