Browse Source

Implementation of SHA256

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

+ 4 - 0
CryptoSwift.xcodeproj/project.pbxproj

@@ -17,6 +17,7 @@
 		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 */; };
+		755409B819A535FA004E7CD9 /* SHA256.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755409B719A535FA004E7CD9 /* SHA256.swift */; };
 		755FB1DA199E347D00475437 /* ExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755FB1D9199E347D00475437 /* ExtensionsTest.swift */; };
 		758F3F761992E57D0014BBDA /* Playground in Resources */ = {isa = PBXBuildFile; fileRef = 758F3F751992E57D0014BBDA /* Playground */; };
 		758F3F781992F6CE0014BBDA /* ByteExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758F3F771992F6CE0014BBDA /* ByteExtension.swift */; };
@@ -103,6 +104,7 @@
 		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>"; };
+		755409B719A535FA004E7CD9 /* SHA256.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SHA256.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>"; };
 		758F3F771992F6CE0014BBDA /* ByteExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ByteExtension.swift; sourceTree = "<group>"; };
@@ -165,6 +167,7 @@
 				754DD76D19A149AF00E52288 /* CryptoHashBase.swift */,
 				750A545F1992D2680017DA75 /* MD5.swift */,
 				752E087A199FF27C005B0EA0 /* SHA1.swift */,
+				755409B719A535FA004E7CD9 /* SHA256.swift */,
 				758F3F771992F6CE0014BBDA /* ByteExtension.swift */,
 				7547195019931802002FA5F1 /* IntExtension.swift */,
 				752DEF7619693EA000E17557 /* NSDataExtension.swift */,
@@ -323,6 +326,7 @@
 				750A54601992D2680017DA75 /* MD5.swift in Sources */,
 				752DEF7719693EA000E17557 /* NSDataExtension.swift in Sources */,
 				754C8FED19979F94005AD904 /* ArrayExtension.swift in Sources */,
+				755409B819A535FA004E7CD9 /* SHA256.swift in Sources */,
 				7547195119931802002FA5F1 /* IntExtension.swift in Sources */,
 				754DD76E19A149AF00E52288 /* CryptoHashBase.swift in Sources */,
 				758F3F781992F6CE0014BBDA /* ByteExtension.swift in Sources */,

+ 2 - 0
CryptoSwift/CryptoHash.swift

@@ -19,6 +19,8 @@ public enum CryptoHash {
             return data.md5()
         case sha1:
             return data.sha1()
+        case sha256:
+            return data.sha256()
             //        case sha224:
             //            return data.sha224()
             //        case sha256:

+ 5 - 0
CryptoSwift/CryptoHashBase.swift

@@ -46,4 +46,9 @@ public class CryptoHashBase {
     internal func rotateLeft(x:UInt32, _ n:UInt32) -> UInt32 {
         return ((x &<< n) & 0xffffffff) | (x &>> (32 - n))
     }
+    
+    internal func rotateRight(x:UInt32, _ n:UInt32) -> UInt32 {
+        return ((x &>> n) & 0xffffffff) | (x &<< (32 - n))
+    }
+
 }

+ 0 - 7
CryptoSwift/MD5.swift

@@ -116,12 +116,5 @@ public class MD5 : CryptoHashBase {
         
         return buf.copy() as NSData;
     }
-
-    //MARK: Class
-    
-    class func calculate(message: NSData) -> NSData
-    {
-        return MD5(message).calculate();
-    }
 }
 

+ 5 - 1
CryptoSwift/NSDataExtension.swift

@@ -43,7 +43,11 @@ extension NSData {
     public func sha1() -> NSData {
         return SHA1(self).calculate()
     }
-    
+
+    public func sha256() -> NSData {
+        return SHA256(self).calculate()
+    }
+
     internal func toHexString() -> String {
         let count = self.length / sizeof(Byte)
         var bytesArray = [Byte](count: count, repeatedValue: 0)

+ 8 - 1
CryptoSwift/Playground/MyPlayground.playground/section-1.swift

@@ -2,7 +2,14 @@
 
 import UIKit
 
-var i:Int = 24
+var i:UInt32 = 402653184
 i.bigEndian
 i.littleEndian
 
+
+var M:[UInt32] = [UInt32](count: 80, repeatedValue: 0)
+for x in 0..<M.count {
+    M[x] = 1
+}
+
+M

+ 1 - 2
CryptoSwift/SHA1.swift

@@ -33,9 +33,8 @@ public class SHA1 : CryptoHashBase {
             for x in 0..<M.count {
                 switch (x) {
                 case 0...15:
-                    var range = NSRange(location:x * wordSize, length: wordSize)
                     var le:UInt32 = 0
-                    chunk.getBytes(&le, range:range);
+                    chunk.getBytes(&le, range:NSRange(location:x * wordSize, length: wordSize));
                     M[x] = le.bigEndian
                     break
                 default:

+ 102 - 0
CryptoSwift/SHA256.swift

@@ -0,0 +1,102 @@
+//
+//  SHA256.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 20/08/14.
+//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
+//
+
+import Foundation
+
+public class SHA256 : CryptoHashBase {
+    private let h:[UInt32] = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]
+    private let k:[UInt32] = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+                            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+                            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+                            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+                            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+                            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+                            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+                            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]
+    
+    public func calculate() -> NSData {
+        var tmpMessage = self.prepare()
+        let wordSize = sizeof(UInt32)
+        
+        // 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));
+        
+        // Process the message in successive 512-bit chunks:
+        let chunkSizeBytes = 512 / 8 // 64
+        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, big-endian
+            // Extend the sixteen 32-bit words into sixty-four 32-bit words:
+            var M:[UInt32] = [UInt32](count: 64, repeatedValue: 0)
+            for x in 0..<M.count {
+                switch (x) {
+                case 0...15:
+                    var le:UInt32 = 0
+                    chunk.getBytes(&le, range:NSRange(location:x * wordSize, length: wordSize));
+                    M[x] = le.bigEndian
+                    break
+                default:
+                    let s0 = rotateRight(M[x-15], 7) ^ rotateRight(M[x-15], 18) ^ (M[x-15] >> 3)
+                    let s1 = rotateRight(M[x-2], 17) ^ rotateRight(M[x-2], 19) ^ (M[x-2] >> 10)
+                    M[x] = M[x-16] &+ s0 &+ M[x-7] &+ s1
+                    break
+                }
+            }
+            
+            var A = hh[0]
+            var B = hh[1]
+            var C = hh[2]
+            var D = hh[3]
+            var E = hh[4]
+            var F = hh[5]
+            var G = hh[6]
+            var H = hh[7]
+            
+            // Main loop
+            for j in 0...63 {
+                let s0 = rotateRight(A,2) ^ rotateRight(A,13) ^ rotateRight(A,22)
+                let maj = (A & B) ^ (A & C) ^ (B & C)
+                let t2 = s0 &+ maj
+                let s1 = rotateRight(E,6) ^ rotateRight(E,11) ^ rotateRight(E,25)
+                let ch = (E & F) ^ ((~E) & G)
+                let t1 = H &+ s1 &+ ch &+ k[j] &+ M[j]
+                
+                H = G
+                G = F
+                F = E
+                E = D &+ t1
+                D = C
+                C = B
+                B = A
+                A = t1 &+ t2
+            }
+            
+            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
+            hh[5] = (hh[5] &+ F) & 0xffffffff
+            hh[6] = (hh[6] &+ G) & 0xffffffff
+            hh[7] = (hh[7] &+ H) & 0xffffffff
+        }
+        
+        // Produce the final hash value (big-endian) as a 160 bit number:
+        var buf: NSMutableData = NSMutableData();
+        hh.map({ (item) -> () in
+            var i:UInt32 = item.bigEndian
+            buf.appendBytes(&i, length: sizeof(UInt32))
+        })
+        
+        return buf.copy() as NSData;
+    }
+}

+ 8 - 0
CryptoSwift/StringExtension.swift

@@ -25,4 +25,12 @@ extension String {
         }
         return nil
     }
+
+    public func sha256() -> String? {
+        if let stringData = self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
+            return stringData.sha256().toHexString()
+        }
+        return nil
+    }
+
 }

+ 14 - 1
CryptoSwiftTests/HashTests.swift

@@ -69,7 +69,20 @@ class CryptoSwiftTests: XCTestCase {
         if let hash = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha1() {
             XCTAssertEqual(hash, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1", "SHA1 calculation failed")
         }
-
+    }
+    
+    func testSHA256() {
+        var data:NSData = NSData(bytes: [0x31, 0x32, 0x33] as [Byte], length: 3)
+        var hash:NSData = data.sha256()
+        XCTAssertEqual(hash.hexString, "A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3", "SHA256 calculation failed");
+        
+        if let hash = "Rosetta code".sha256() {
+            XCTAssertEqual(hash, "764FAF5C61AC315F1497F9DFA542713965B785E5CC2F707D6468D7D1124CDFCF", "SHA1 calculation failed")
+        }
+//
+//        if let hash = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha1() {
+//            XCTAssertEqual(hash, "84983E441C3BD26EBAAE4AA1F95129E5E54670F1", "SHA1 calculation failed")
+//        }
     }
 //
 //    func testSHA512() {

+ 7 - 4
README.md

@@ -9,9 +9,10 @@ Good mood
 - Easy to use
 - Convenience extensions
 
-######what implemented
+#####what implemented?
 - MD5
 - SHA1
+- SHA256
 
 ##Usage
 
@@ -30,12 +31,14 @@ Generally you should use `CryptoHash` enum or convenience extensions
 	let hash = MD5(data).calculate()
 	let hash = data.md5()
 	let hash = data.sha1()
+	let hash = data.sha256()
 	
-srtaight from String
+	println(hash.hexString)
+	
+straight from String
 
     /* Calculate hash for string with convenience extension */
-    var string:String = "123"
-    if let hash = string.md5() {
+    if let hash = "123".md5() {
         println(string.md5())
     }