Browse Source

CryptoHashBase class. SHA1 fix and tests.

Marcin Krzyżanowski 11 năm trước cách đây
mục cha
commit
c1959fa960

+ 4 - 0
CryptoSwift.xcodeproj/project.pbxproj

@@ -15,6 +15,7 @@
 		754BE45B19693E190098E6F3 /* CryptoSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 754BE45A19693E190098E6F3 /* CryptoSwift.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		754BE46819693E190098E6F3 /* HashTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754BE46719693E190098E6F3 /* HashTests.swift */; };
 		754C8FED19979F94005AD904 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754C8FEC19979F94005AD904 /* ArrayExtension.swift */; };
+		754DD76E19A149AF00E52288 /* CryptoHashBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754DD76D19A149AF00E52288 /* CryptoHashBase.swift */; };
 		7552614E1993051E000D2B20 /* CryptoHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7552614D1993051E000D2B20 /* CryptoHash.swift */; };
 		755FB1DA199E347D00475437 /* ExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755FB1D9199E347D00475437 /* ExtensionsTest.swift */; };
 		758F3F761992E57D0014BBDA /* Playground in Resources */ = {isa = PBXBuildFile; fileRef = 758F3F751992E57D0014BBDA /* Playground */; };
@@ -100,6 +101,7 @@
 		754BE46619693E190098E6F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		754BE46719693E190098E6F3 /* HashTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashTests.swift; sourceTree = "<group>"; };
 		754C8FEC19979F94005AD904 /* ArrayExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = "<group>"; };
+		754DD76D19A149AF00E52288 /* CryptoHashBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CryptoHashBase.swift; sourceTree = "<group>"; };
 		7552614D1993051E000D2B20 /* CryptoHash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CryptoHash.swift; sourceTree = "<group>"; };
 		755FB1D9199E347D00475437 /* ExtensionsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionsTest.swift; sourceTree = "<group>"; };
 		758F3F751992E57D0014BBDA /* Playground */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Playground; path = CryptoSwift/Playground; sourceTree = "<group>"; };
@@ -160,6 +162,7 @@
 			children = (
 				754BE45A19693E190098E6F3 /* CryptoSwift.h */,
 				7552614D1993051E000D2B20 /* CryptoHash.swift */,
+				754DD76D19A149AF00E52288 /* CryptoHashBase.swift */,
 				750A545F1992D2680017DA75 /* MD5.swift */,
 				752E087A199FF27C005B0EA0 /* SHA1.swift */,
 				758F3F771992F6CE0014BBDA /* ByteExtension.swift */,
@@ -321,6 +324,7 @@
 				752DEF7719693EA000E17557 /* NSDataExtension.swift in Sources */,
 				754C8FED19979F94005AD904 /* ArrayExtension.swift in Sources */,
 				7547195119931802002FA5F1 /* IntExtension.swift in Sources */,
+				754DD76E19A149AF00E52288 /* CryptoHashBase.swift in Sources */,
 				758F3F781992F6CE0014BBDA /* ByteExtension.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 44 - 0
CryptoSwift/CryptoHashBase.swift

@@ -0,0 +1,44 @@
+//
+//  Hash.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 17/08/14.
+//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
+//
+
+import Foundation
+
+public class CryptoHashBase {
+    
+    internal var message: NSData
+    
+    //MARK: Public
+    
+    public init(_ message: NSData) {
+        self.message = message
+    }
+    
+    /** Common part for hash calculation. Prepare header data. */
+    internal func prepare() -> NSMutableData {
+        var tmpMessage: NSMutableData = NSMutableData(data: self.message)
+        
+        // Step 1. Append Padding Bits
+        tmpMessage.appendBytes([0x80]) // append one bit (Byte with one bit) to message
+        
+        // append "0" bit until message length in bits ≡ 448 (mod 512)
+        while tmpMessage.length % 64 != 56 {
+            tmpMessage.appendBytes([0x00])
+        }
+        
+        return tmpMessage
+    }
+    
+    internal func reverseBytes(value: UInt32) -> UInt32 {
+        return (value & 0x000000FF) << 24 | (value & 0x0000FF00) << 8 |
+            (value & 0x00FF0000) >> 8  | (value & 0xFF000000) >> 24;
+    }
+    
+    internal func rotateLeft(x:UInt32, _ n:UInt32) -> UInt32 {
+        return ((x &<< n) & 0xffffffff) | (x &>> (32 - n))
+    }
+}

+ 23 - 45
CryptoSwift/MD5.swift

@@ -8,7 +8,7 @@
 
 import Foundation
 
-public class MD5 {
+public class MD5 : CryptoHashBase {
 
     /** specifies the per-round shift amounts */
     private let s: [UInt32] = [7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
@@ -34,41 +34,25 @@ public class MD5 {
                        0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,
                        0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391]
     
-    let a0: UInt32 = 0x67452301
-    let b0: UInt32 = 0xefcdab89
-    let c0: UInt32 = 0x98badcfe
-    let d0: UInt32 = 0x10325476
-    
-    private var message: NSData
+    private let h:[UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]
+//    private let a0: UInt32 = 0x67452301
+//    private let b0: UInt32 = 0xefcdab89
+//    private let c0: UInt32 = 0x98badcfe
+//    private let d0: UInt32 = 0x10325476
     
     //MARK: Public
-    
-    public init(_ message: NSData) {
-        self.message = message
-    }
-    
     public func calculate() -> NSData? {
-        var tmpMessage: NSMutableData = NSMutableData(data: message)
+        var tmpMessage = prepare()
         let wordSize = sizeof(UInt32)
-        
-        var aa = a0
-        var bb = b0
-        var cc = c0
-        var dd = d0
-        
-        // Step 1. Append Padding Bits
-        tmpMessage.appendBytes([0x80]) // append one bit (Byte with one bit) to message
-        
-        // append "0" bit until message length in bits ≡ 448 (mod 512)
-        while tmpMessage.length % 64 != 56 {
-            tmpMessage.appendBytes([0x00])
-        }
+
+        // hash values
+        var hh = h
         
         // Step 2. Append Length a 64-bit representation of lengthInBits
         var lengthInBits = (message.length * 8)
         var lengthBytes = lengthInBits.bytes(64 / 8)
         tmpMessage.appendBytes(reverse(lengthBytes));
-        
+
         // Process the message in successive 512-bit chunks:
         let chunkSizeBytes = 512 / 8 // 64
         var leftMessageBytes = tmpMessage.length
@@ -83,10 +67,10 @@ public class MD5 {
             }
             
             // Initialize hash value for this chunk:
-            var A:UInt32 = aa
-            var B:UInt32 = bb
-            var C:UInt32 = cc
-            var D:UInt32 = dd
+            var A:UInt32 = hh[0]
+            var B:UInt32 = hh[1]
+            var C:UInt32 = hh[2]
+            var D:UInt32 = hh[3]
             
             var dTemp:UInt32 = 0
             
@@ -122,17 +106,17 @@ public class MD5 {
                 A = dTemp    
             }
             
-            aa = aa &+ A
-            bb = bb &+ B
-            cc = cc &+ C
-            dd = dd &+ D
+            hh[0] = hh[0] &+ A
+            hh[1] = hh[1] &+ B
+            hh[2] = hh[2] &+ C
+            hh[3] = hh[3] &+ D
         }
 
         var buf: NSMutableData = NSMutableData();
-        buf.appendBytes(&aa, length: wordSize)
-        buf.appendBytes(&bb, length: wordSize)
-        buf.appendBytes(&cc, length: wordSize)
-        buf.appendBytes(&dd, length: wordSize)
+        hh.map({ (item) -> () in
+            var i:UInt32 = item.littleEndian
+            buf.appendBytes(&i, length: sizeof(UInt32))
+        })
         
         return buf.copy() as? NSData;
     }
@@ -143,11 +127,5 @@ public class MD5 {
     {
         return MD5(message).calculate();
     }
-    
-    //MARK: Private
-    
-    private func rotateLeft(x:UInt32, _ n:UInt32) -> UInt32 {
-        return (x &<< n) | (x &>> (32 - n))
-    }
 }
 

+ 17 - 48
CryptoSwift/SHA1.swift

@@ -8,34 +8,16 @@
 
 import Foundation
 
-public class SHA1 {
+public class SHA1 : CryptoHashBase {
     
     private let h:[UInt32] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
-    private var message: NSData;
-    
-    public init(_ message: NSData) {
-        self.message = message
-    }
-    
+        
     public func calculate() -> NSData? {
+        var tmpMessage = self.prepare()
         let wordSize = sizeof(UInt32)
         
-        var h0 = h[0]
-        var h1 = h[1]
-        var h2 = h[2]
-        var h3 = h[3]
-        var h4 = h[4]
-        
-        // make it big-endian
-        var tmpMessage: NSMutableData = NSMutableData(data: message)
-        
-        // append one bit (Byte with one bit) to message
-        tmpMessage.appendBytes([0x80])
-
-        // append "0" bit until message length in bits ≡ 448 (mod 512)
-        while tmpMessage.length % 64 != 56 {
-            tmpMessage.appendBytes([0x00])
-        }
+        // hash values
+        var hh = h
         
         // append message length, in a 64-bit big-endian integer. So now the message length is a multiple of 512 bits.
         tmpMessage.appendBytes((message.length * 8).bytes(64 / 8));
@@ -62,12 +44,11 @@ public class SHA1 {
                 }
             }
             
-            var A = h0
-            var B = h1
-            var C = h2
-            var D = h3
-            var E = h4
-            
+            var A = hh[0]
+            var B = hh[1]
+            var C = hh[2]
+            var D = hh[3]
+            var E = hh[4]
             
             // Main loop
             for j in 0...79 {
@@ -104,32 +85,20 @@ public class SHA1 {
                 
             }
             
-            h0 = (h0 &+ A) & 0xffffffff
-            h1 = (h1 &+ B) & 0xffffffff
-            h2 = (h2 &+ C) & 0xffffffff
-            h3 = (h3 &+ D) & 0xffffffff
-            h4 = (h4 &+ E) & 0xffffffff
+            hh[0] = (hh[0] &+ A) & 0xffffffff
+            hh[1] = (hh[1] &+ B) & 0xffffffff
+            hh[2] = (hh[2] &+ C) & 0xffffffff
+            hh[3] = (hh[3] &+ D) & 0xffffffff
+            hh[4] = (hh[4] &+ E) & 0xffffffff
         }
         
         // Produce the final hash value (big-endian) as a 160 bit number:
         var buf: NSMutableData = NSMutableData();
-        [h0, h1, h2, h3, h4].map({ (item) -> () in
+        hh.map({ (item) -> () in
             var i:UInt32 = item.bigEndian
             buf.appendBytes(&i, length: sizeof(UInt32))
         })
         
         return buf.copy() as? NSData;
-    }
-    
-    //MARK: Private
-    
-    private func reverseBytes(value: UInt32) -> UInt32
-    {
-        return (value & 0x000000FF) << 24 | (value & 0x0000FF00) << 8 |
-               (value & 0x00FF0000) >> 8  | (value & 0xFF000000) >> 24;
-    }
-    
-    private func rotateLeft(x:UInt32, _ n:UInt32) -> UInt32 {
-        return ((x &<< n) & 0xffffffff) | (x &>> (32 - n))
-    }
+    }    
 }

+ 10 - 2
CryptoSwift/StringExtension.swift

@@ -14,8 +14,16 @@ extension String {
     /** Calculate MD5 hash */
     public func md5() -> String? {
         var stringData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
-        if var data = stringData!.md5() {
-            return data.hexString
+        if let hash = stringData!.md5() {
+            return hash.hexString
+        }
+        return nil
+    }
+    
+    public func sha1() -> String? {
+        var stringData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
+        if let hash = stringData!.sha1() {
+            return hash.hexString
         }
         return nil
     }

+ 9 - 0
CryptoSwiftTests/HashTests.swift

@@ -64,6 +64,15 @@ class CryptoSwiftTests: XCTestCase {
         if let hash = data.sha1() {
             XCTAssertEqual(hash.hexString, "40BD001563085FC35165329EA1FF5C5ECBDBBEEF", "SHA1 calculation failed");
         }
+        
+        if let hash = "abc".sha1() {
+            XCTAssertEqual(hash, "A9993E364706816ABA3E25717850C26C9CD0D89D", "SHA1 calculation failed")
+        }
+
+        if let hash = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha1() {
+            XCTAssertEqual(hash, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1", "SHA1 calculation failed")
+        }
+
     }
 //
 //    func testSHA512() {