Browse Source

Merge branch 'develop'

Marcin Krzyżanowski 9 years ago
parent
commit
cdc0972f98

+ 98 - 10
CryptoSwift.xcodeproj/project.pbxproj

@@ -79,10 +79,6 @@
 		757BC9591C1CA5790093AAA9 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9211C1CA5790093AAA9 /* Cipher.swift */; };
 		757BC95A1C1CA5790093AAA9 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9211C1CA5790093AAA9 /* Cipher.swift */; };
 		757BC95B1C1CA5790093AAA9 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9211C1CA5790093AAA9 /* Cipher.swift */; };
-		757BC95C1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9221C1CA5790093AAA9 /* CipherBlockMode.swift */; };
-		757BC95D1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9221C1CA5790093AAA9 /* CipherBlockMode.swift */; };
-		757BC95E1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9221C1CA5790093AAA9 /* CipherBlockMode.swift */; };
-		757BC95F1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9221C1CA5790093AAA9 /* CipherBlockMode.swift */; };
 		757BC9601C1CA5790093AAA9 /* CRC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9231C1CA5790093AAA9 /* CRC.swift */; };
 		757BC9611C1CA5790093AAA9 /* CRC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9231C1CA5790093AAA9 /* CRC.swift */; };
 		757BC9621C1CA5790093AAA9 /* CRC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC9231C1CA5790093AAA9 /* CRC.swift */; };
@@ -179,9 +175,45 @@
 		757DA2551A4ED408002BA3EF /* AESTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2541A4ED408002BA3EF /* AESTests.swift */; };
 		757DA2571A4ED47B002BA3EF /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2561A4ED47B002BA3EF /* Helpers.swift */; };
 		757DA2591A4ED4D7002BA3EF /* ChaCha20Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */; };
+		7588034C1C8F8C33008C1576 /* BlockModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* BlockModeGenerator.swift */; };
+		7588034D1C8F8C42008C1576 /* BlockModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* BlockModeGenerator.swift */; };
+		7588034E1C8F8C42008C1576 /* BlockModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* BlockModeGenerator.swift */; };
+		7588034F1C8F8C43008C1576 /* BlockModeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7588034B1C8F8C33008C1576 /* BlockModeGenerator.swift */; };
 		758A94281A65C59200E46135 /* HMACTests.swift in Resources */ = {isa = PBXBuildFile; fileRef = 758A94271A65C59200E46135 /* HMACTests.swift */; };
 		758A94291A65C67400E46135 /* HMACTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758A94271A65C59200E46135 /* HMACTests.swift */; };
+		758F58F11C8FB6E20054C377 /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758F58F01C8FB6E20054C377 /* OFB.swift */; };
+		758F58F21C8FB6E20054C377 /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758F58F01C8FB6E20054C377 /* OFB.swift */; };
+		758F58F31C8FB6E20054C377 /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758F58F01C8FB6E20054C377 /* OFB.swift */; };
+		758F58F41C8FB6E20054C377 /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758F58F01C8FB6E20054C377 /* OFB.swift */; };
 		75B601EB197D6A6C0009B53D /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; };
+		75CB93251C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
+		75CB93261C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
+		75CB93271C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
+		75CB93281C8F5EC10087740D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93241C8F5EC10087740D /* CBC.swift */; };
+		75CB93301C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
+		75CB93311C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
+		75CB93321C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
+		75CB93331C8F5F580087740D /* CipherBlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB932F1C8F5F580087740D /* CipherBlockMode.swift */; };
+		75CB93351C8F5FCE0087740D /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93341C8F5FCE0087740D /* PCBC.swift */; };
+		75CB93361C8F5FCE0087740D /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93341C8F5FCE0087740D /* PCBC.swift */; };
+		75CB93371C8F5FCE0087740D /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93341C8F5FCE0087740D /* PCBC.swift */; };
+		75CB93381C8F5FCE0087740D /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93341C8F5FCE0087740D /* PCBC.swift */; };
+		75CB933A1C8F5FFD0087740D /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93391C8F5FFD0087740D /* CFB.swift */; };
+		75CB933B1C8F5FFD0087740D /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93391C8F5FFD0087740D /* CFB.swift */; };
+		75CB933C1C8F5FFD0087740D /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93391C8F5FFD0087740D /* CFB.swift */; };
+		75CB933D1C8F5FFD0087740D /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93391C8F5FFD0087740D /* CFB.swift */; };
+		75CB93441C8F603C0087740D /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93431C8F603C0087740D /* CTR.swift */; };
+		75CB93451C8F603C0087740D /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93431C8F603C0087740D /* CTR.swift */; };
+		75CB93461C8F603C0087740D /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93431C8F603C0087740D /* CTR.swift */; };
+		75CB93471C8F603C0087740D /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93431C8F603C0087740D /* CTR.swift */; };
+		75CB93491C8F60700087740D /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93481C8F60700087740D /* ECB.swift */; };
+		75CB934A1C8F60700087740D /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93481C8F60700087740D /* ECB.swift */; };
+		75CB934B1C8F60700087740D /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93481C8F60700087740D /* ECB.swift */; };
+		75CB934C1C8F60700087740D /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB93481C8F60700087740D /* ECB.swift */; };
+		75CB934E1C8F609D0087740D /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB934D1C8F609D0087740D /* BlockModeOptions.swift */; };
+		75CB934F1C8F609D0087740D /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB934D1C8F609D0087740D /* BlockModeOptions.swift */; };
+		75CB93501C8F609D0087740D /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB934D1C8F609D0087740D /* BlockModeOptions.swift */; };
+		75CB93511C8F609D0087740D /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CB934D1C8F609D0087740D /* BlockModeOptions.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -293,7 +325,6 @@
 		757BC91F1C1CA5790093AAA9 /* BytesSequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BytesSequence.swift; path = Sources/CryptoSwift/BytesSequence.swift; sourceTree = SOURCE_ROOT; };
 		757BC9201C1CA5790093AAA9 /* ChaCha20.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChaCha20.swift; path = Sources/CryptoSwift/ChaCha20.swift; sourceTree = SOURCE_ROOT; };
 		757BC9211C1CA5790093AAA9 /* Cipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cipher.swift; path = Sources/CryptoSwift/Cipher.swift; sourceTree = SOURCE_ROOT; };
-		757BC9221C1CA5790093AAA9 /* CipherBlockMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CipherBlockMode.swift; path = Sources/CryptoSwift/CipherBlockMode.swift; sourceTree = SOURCE_ROOT; };
 		757BC9231C1CA5790093AAA9 /* CRC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CRC.swift; path = Sources/CryptoSwift/CRC.swift; sourceTree = SOURCE_ROOT; };
 		757BC9251C1CA5790093AAA9 /* CSArrayType+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CSArrayType+Extensions.swift"; path = "Sources/CryptoSwift/CSArrayType+Extensions.swift"; sourceTree = SOURCE_ROOT; };
 		757BC9261C1CA5790093AAA9 /* Generics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Generics.swift; path = Sources/CryptoSwift/Generics.swift; sourceTree = SOURCE_ROOT; };
@@ -322,7 +353,16 @@
 		757DA2541A4ED408002BA3EF /* AESTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESTests.swift; sourceTree = "<group>"; };
 		757DA2561A4ED47B002BA3EF /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
 		757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChaCha20Tests.swift; sourceTree = "<group>"; };
+		7588034B1C8F8C33008C1576 /* BlockModeGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockModeGenerator.swift; path = Sources/CryptoSwift/BlockMode/BlockModeGenerator.swift; sourceTree = SOURCE_ROOT; };
 		758A94271A65C59200E46135 /* HMACTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACTests.swift; sourceTree = "<group>"; };
+		758F58F01C8FB6E20054C377 /* OFB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OFB.swift; path = Sources/CryptoSwift/BlockMode/OFB.swift; sourceTree = SOURCE_ROOT; };
+		75CB93241C8F5EC10087740D /* CBC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CBC.swift; path = Sources/CryptoSwift/BlockMode/CBC.swift; sourceTree = SOURCE_ROOT; };
+		75CB932F1C8F5F580087740D /* CipherBlockMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CipherBlockMode.swift; path = Sources/CryptoSwift/BlockMode/CipherBlockMode.swift; sourceTree = SOURCE_ROOT; };
+		75CB93341C8F5FCE0087740D /* PCBC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PCBC.swift; path = Sources/CryptoSwift/BlockMode/PCBC.swift; sourceTree = SOURCE_ROOT; };
+		75CB93391C8F5FFD0087740D /* CFB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CFB.swift; path = Sources/CryptoSwift/BlockMode/CFB.swift; sourceTree = SOURCE_ROOT; };
+		75CB93431C8F603C0087740D /* CTR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CTR.swift; path = Sources/CryptoSwift/BlockMode/CTR.swift; sourceTree = SOURCE_ROOT; };
+		75CB93481C8F60700087740D /* ECB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ECB.swift; path = Sources/CryptoSwift/BlockMode/ECB.swift; sourceTree = SOURCE_ROOT; };
+		75CB934D1C8F609D0087740D /* BlockModeOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockModeOptions.swift; path = Sources/CryptoSwift/BlockMode/BlockModeOptions.swift; sourceTree = SOURCE_ROOT; };
 		75D614BF1BD844F2001358B2 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		75DF77721BC8EB59006E9520 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
@@ -407,7 +447,7 @@
 				757BC91F1C1CA5790093AAA9 /* BytesSequence.swift */,
 				757BC9201C1CA5790093AAA9 /* ChaCha20.swift */,
 				757BC9211C1CA5790093AAA9 /* Cipher.swift */,
-				757BC9221C1CA5790093AAA9 /* CipherBlockMode.swift */,
+				75CB93291C8F5EC60087740D /* BlockMode */,
 				757BC9231C1CA5790093AAA9 /* CRC.swift */,
 				757BC9251C1CA5790093AAA9 /* CSArrayType+Extensions.swift */,
 				757BC9261C1CA5790093AAA9 /* Generics.swift */,
@@ -488,6 +528,22 @@
 			path = Sources/CryptoSwift/Foundation;
 			sourceTree = SOURCE_ROOT;
 		};
+		75CB93291C8F5EC60087740D /* BlockMode */ = {
+			isa = PBXGroup;
+			children = (
+				7588034B1C8F8C33008C1576 /* BlockModeGenerator.swift */,
+				75CB934D1C8F609D0087740D /* BlockModeOptions.swift */,
+				75CB932F1C8F5F580087740D /* CipherBlockMode.swift */,
+				75CB93241C8F5EC10087740D /* CBC.swift */,
+				75CB93341C8F5FCE0087740D /* PCBC.swift */,
+				75CB93391C8F5FFD0087740D /* CFB.swift */,
+				758F58F01C8FB6E20054C377 /* OFB.swift */,
+				75CB93431C8F603C0087740D /* CTR.swift */,
+				75CB93481C8F60700087740D /* ECB.swift */,
+			);
+			name = BlockMode;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -719,12 +775,17 @@
 				757BC94D1C1CA5790093AAA9 /* BitExtension.swift in Sources */,
 				757BC9491C1CA5790093AAA9 /* Authenticator.swift in Sources */,
 				757BC9C11C1CA5790093AAA9 /* Utils.swift in Sources */,
+				75CB934A1C8F60700087740D /* ECB.swift in Sources */,
 				757BC9751C1CA5790093AAA9 /* HashProtocol.swift in Sources */,
 				757BC9071C1CA56A0093AAA9 /* ChaCha20+Foundation.swift in Sources */,
 				757BC9851C1CA5790093AAA9 /* IntExtension.swift in Sources */,
 				757BC9B11C1CA5790093AAA9 /* String+Extension.swift in Sources */,
 				757BC96D1C1CA5790093AAA9 /* Generics.swift in Sources */,
+				75CB93261C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9711C1CA5790093AAA9 /* Hash.swift in Sources */,
+				75CB93361C8F5FCE0087740D /* PCBC.swift in Sources */,
+				7588034D1C8F8C42008C1576 /* BlockModeGenerator.swift in Sources */,
+				75CB93311C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9171C1CA56A0093AAA9 /* Utils+Foundation.swift in Sources */,
 				757BC9B51C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,
 				757BC9411C1CA5790093AAA9 /* Array+Extension.swift in Sources */,
@@ -732,19 +793,22 @@
 				757BC9691C1CA5790093AAA9 /* CSArrayType+Extensions.swift in Sources */,
 				757BC9611C1CA5790093AAA9 /* CRC.swift in Sources */,
 				757BC9A11C1CA5790093AAA9 /* Poly1305.swift in Sources */,
+				75CB93451C8F603C0087740D /* CTR.swift in Sources */,
 				757BC9451C1CA5790093AAA9 /* ArraySliceUInt8+Bytes.swift in Sources */,
+				758F58F21C8FB6E20054C377 /* OFB.swift in Sources */,
 				757BC9BD1C1CA5790093AAA9 /* UInt64Extension.swift in Sources */,
 				757BC9991C1CA5790093AAA9 /* PKCS5.swift in Sources */,
+				75CB934F1C8F609D0087740D /* BlockModeOptions.swift in Sources */,
 				757BC9811C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9511C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9891C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9A91C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9911C1CA5790093AAA9 /* Operators.swift in Sources */,
+				75CB933B1C8F5FFD0087740D /* CFB.swift in Sources */,
 				757BC9B91C1CA5790093AAA9 /* UInt32Extension.swift in Sources */,
 				757BC9131C1CA56A0093AAA9 /* String+FoundationExtension.swift in Sources */,
 				757BC98D1C1CA5790093AAA9 /* Multiplatform.swift in Sources */,
 				757BC93D1C1CA5790093AAA9 /* AES.swift in Sources */,
-				757BC95D1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */,
 				757BC9551C1CA5790093AAA9 /* ChaCha20.swift in Sources */,
 				757BC9951C1CA5790093AAA9 /* Padding.swift in Sources */,
 				757BC9A51C1CA5790093AAA9 /* Rabbit.swift in Sources */,
@@ -766,12 +830,16 @@
 				757BC94C1C1CA5790093AAA9 /* BitExtension.swift in Sources */,
 				757BC9481C1CA5790093AAA9 /* Authenticator.swift in Sources */,
 				757BC9C01C1CA5790093AAA9 /* Utils.swift in Sources */,
+				75CB93491C8F60700087740D /* ECB.swift in Sources */,
 				757BC9741C1CA5790093AAA9 /* HashProtocol.swift in Sources */,
 				757BC90E1C1CA56A0093AAA9 /* Rabbit+Foundation.swift in Sources */,
 				757BC9841C1CA5790093AAA9 /* IntExtension.swift in Sources */,
 				757BC9B01C1CA5790093AAA9 /* String+Extension.swift in Sources */,
 				757BC96C1C1CA5790093AAA9 /* Generics.swift in Sources */,
+				75CB93251C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9701C1CA5790093AAA9 /* Hash.swift in Sources */,
+				75CB93351C8F5FCE0087740D /* PCBC.swift in Sources */,
+				75CB93301C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9121C1CA56A0093AAA9 /* String+FoundationExtension.swift in Sources */,
 				757BC9B41C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,
 				757BC9401C1CA5790093AAA9 /* Array+Extension.swift in Sources */,
@@ -779,19 +847,23 @@
 				757BC9681C1CA5790093AAA9 /* CSArrayType+Extensions.swift in Sources */,
 				757BC9601C1CA5790093AAA9 /* CRC.swift in Sources */,
 				757BC9A01C1CA5790093AAA9 /* Poly1305.swift in Sources */,
+				75CB93441C8F603C0087740D /* CTR.swift in Sources */,
 				757BC9441C1CA5790093AAA9 /* ArraySliceUInt8+Bytes.swift in Sources */,
 				757BC9BC1C1CA5790093AAA9 /* UInt64Extension.swift in Sources */,
+				758F58F11C8FB6E20054C377 /* OFB.swift in Sources */,
 				757BC9981C1CA5790093AAA9 /* PKCS5.swift in Sources */,
+				75CB934E1C8F609D0087740D /* BlockModeOptions.swift in Sources */,
 				757BC9801C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9501C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC9881C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9A81C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9901C1CA5790093AAA9 /* Operators.swift in Sources */,
+				75CB933A1C8F5FFD0087740D /* CFB.swift in Sources */,
+				7588034C1C8F8C33008C1576 /* BlockModeGenerator.swift in Sources */,
 				757BC9B81C1CA5790093AAA9 /* UInt32Extension.swift in Sources */,
 				757BC8FE1C1CA56A0093AAA9 /* AES+Foundation.swift in Sources */,
 				757BC98C1C1CA5790093AAA9 /* Multiplatform.swift in Sources */,
 				757BC93C1C1CA5790093AAA9 /* AES.swift in Sources */,
-				757BC95C1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */,
 				757BC9541C1CA5790093AAA9 /* ChaCha20.swift in Sources */,
 				757BC9941C1CA5790093AAA9 /* Padding.swift in Sources */,
 				757BC9A41C1CA5790093AAA9 /* Rabbit.swift in Sources */,
@@ -829,12 +901,17 @@
 				757BC94E1C1CA5790093AAA9 /* BitExtension.swift in Sources */,
 				757BC94A1C1CA5790093AAA9 /* Authenticator.swift in Sources */,
 				757BC9C21C1CA5790093AAA9 /* Utils.swift in Sources */,
+				75CB934B1C8F60700087740D /* ECB.swift in Sources */,
 				757BC9761C1CA5790093AAA9 /* HashProtocol.swift in Sources */,
 				757BC9101C1CA56A0093AAA9 /* Rabbit+Foundation.swift in Sources */,
 				757BC9861C1CA5790093AAA9 /* IntExtension.swift in Sources */,
 				757BC9B21C1CA5790093AAA9 /* String+Extension.swift in Sources */,
 				757BC96E1C1CA5790093AAA9 /* Generics.swift in Sources */,
+				75CB93271C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9721C1CA5790093AAA9 /* Hash.swift in Sources */,
+				75CB93371C8F5FCE0087740D /* PCBC.swift in Sources */,
+				7588034E1C8F8C42008C1576 /* BlockModeGenerator.swift in Sources */,
+				75CB93321C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9141C1CA56A0093AAA9 /* String+FoundationExtension.swift in Sources */,
 				757BC9B61C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,
 				757BC9421C1CA5790093AAA9 /* Array+Extension.swift in Sources */,
@@ -842,19 +919,22 @@
 				757BC96A1C1CA5790093AAA9 /* CSArrayType+Extensions.swift in Sources */,
 				757BC9621C1CA5790093AAA9 /* CRC.swift in Sources */,
 				757BC9A21C1CA5790093AAA9 /* Poly1305.swift in Sources */,
+				75CB93461C8F603C0087740D /* CTR.swift in Sources */,
 				757BC9461C1CA5790093AAA9 /* ArraySliceUInt8+Bytes.swift in Sources */,
+				758F58F31C8FB6E20054C377 /* OFB.swift in Sources */,
 				757BC9BE1C1CA5790093AAA9 /* UInt64Extension.swift in Sources */,
 				757BC99A1C1CA5790093AAA9 /* PKCS5.swift in Sources */,
+				75CB93501C8F609D0087740D /* BlockModeOptions.swift in Sources */,
 				757BC9821C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9521C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC98A1C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9AA1C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9921C1CA5790093AAA9 /* Operators.swift in Sources */,
+				75CB933C1C8F5FFD0087740D /* CFB.swift in Sources */,
 				757BC9BA1C1CA5790093AAA9 /* UInt32Extension.swift in Sources */,
 				757BC9001C1CA56A0093AAA9 /* AES+Foundation.swift in Sources */,
 				757BC98E1C1CA5790093AAA9 /* Multiplatform.swift in Sources */,
 				757BC93E1C1CA5790093AAA9 /* AES.swift in Sources */,
-				757BC95E1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */,
 				757BC9561C1CA5790093AAA9 /* ChaCha20.swift in Sources */,
 				757BC9961C1CA5790093AAA9 /* Padding.swift in Sources */,
 				757BC9A61C1CA5790093AAA9 /* Rabbit.swift in Sources */,
@@ -876,12 +956,17 @@
 				757BC94F1C1CA5790093AAA9 /* BitExtension.swift in Sources */,
 				757BC94B1C1CA5790093AAA9 /* Authenticator.swift in Sources */,
 				757BC9C31C1CA5790093AAA9 /* Utils.swift in Sources */,
+				75CB934C1C8F60700087740D /* ECB.swift in Sources */,
 				757BC9771C1CA5790093AAA9 /* HashProtocol.swift in Sources */,
 				757BC9091C1CA56A0093AAA9 /* ChaCha20+Foundation.swift in Sources */,
 				757BC9871C1CA5790093AAA9 /* IntExtension.swift in Sources */,
 				757BC9B31C1CA5790093AAA9 /* String+Extension.swift in Sources */,
 				757BC96F1C1CA5790093AAA9 /* Generics.swift in Sources */,
+				75CB93281C8F5EC10087740D /* CBC.swift in Sources */,
 				757BC9731C1CA5790093AAA9 /* Hash.swift in Sources */,
+				75CB93381C8F5FCE0087740D /* PCBC.swift in Sources */,
+				7588034F1C8F8C43008C1576 /* BlockModeGenerator.swift in Sources */,
+				75CB93331C8F5F580087740D /* CipherBlockMode.swift in Sources */,
 				757BC9191C1CA56A0093AAA9 /* Utils+Foundation.swift in Sources */,
 				757BC9B71C1CA5790093AAA9 /* UInt8Extension.swift in Sources */,
 				757BC9431C1CA5790093AAA9 /* Array+Extension.swift in Sources */,
@@ -889,19 +974,22 @@
 				757BC96B1C1CA5790093AAA9 /* CSArrayType+Extensions.swift in Sources */,
 				757BC9631C1CA5790093AAA9 /* CRC.swift in Sources */,
 				757BC9A31C1CA5790093AAA9 /* Poly1305.swift in Sources */,
+				75CB93471C8F603C0087740D /* CTR.swift in Sources */,
 				757BC9471C1CA5790093AAA9 /* ArraySliceUInt8+Bytes.swift in Sources */,
+				758F58F41C8FB6E20054C377 /* OFB.swift in Sources */,
 				757BC9BF1C1CA5790093AAA9 /* UInt64Extension.swift in Sources */,
 				757BC99B1C1CA5790093AAA9 /* PKCS5.swift in Sources */,
+				75CB93511C8F609D0087740D /* BlockModeOptions.swift in Sources */,
 				757BC9831C1CA5790093AAA9 /* IntegerConvertible.swift in Sources */,
 				757BC9531C1CA5790093AAA9 /* BytesSequence.swift in Sources */,
 				757BC98B1C1CA5790093AAA9 /* MD5.swift in Sources */,
 				757BC9AB1C1CA5790093AAA9 /* SHA1.swift in Sources */,
 				757BC9931C1CA5790093AAA9 /* Operators.swift in Sources */,
+				75CB933D1C8F5FFD0087740D /* CFB.swift in Sources */,
 				757BC9BB1C1CA5790093AAA9 /* UInt32Extension.swift in Sources */,
 				757BC9151C1CA56A0093AAA9 /* String+FoundationExtension.swift in Sources */,
 				757BC98F1C1CA5790093AAA9 /* Multiplatform.swift in Sources */,
 				757BC93F1C1CA5790093AAA9 /* AES.swift in Sources */,
-				757BC95F1C1CA5790093AAA9 /* CipherBlockMode.swift in Sources */,
 				757BC9571C1CA5790093AAA9 /* ChaCha20.swift in Sources */,
 				757BC9971C1CA5790093AAA9 /* Padding.swift in Sources */,
 				757BC9A71C1CA5790093AAA9 /* Rabbit.swift in Sources */,

+ 45 - 2
CryptoSwiftTests/AESTests.swift

@@ -99,7 +99,7 @@ final class AESTests: XCTestCase {
         let decrypted = try! aes.decrypt(encrypted, padding: nil)
         XCTAssertEqual(decrypted, plaintext, "decryption failed")
     }
-    
+
     // https://github.com/krzyzanowskim/CryptoSwift/issues/142
     func testAES_encrypt_cfb_long() {
         let key: [UInt8] = [56, 118, 37, 51, 125, 78, 103, 107, 119, 40, 74, 88, 117, 112, 123, 75, 122, 89, 72, 36, 46, 91, 106, 60, 54, 110, 34, 126, 69, 126, 61, 87]
@@ -109,7 +109,50 @@ final class AESTests: XCTestCase {
         let decrypted: [UInt8] = try! AES(key: key, iv: iv, blockMode: .CFB).decrypt(encrypted)
         XCTAssert(decrypted == plaintext, "decryption failed")
     }
-    
+
+    func testAES_encrypt_ofb128() {
+        let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
+        let iv:[UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
+        let plaintext:[UInt8] = [0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a]
+        let expected:[UInt8] = [0x3b,0x3f,0xd9,0x2e,0xb7,0x2d,0xad,0x20,0x33,0x34,0x49,0xf8,0xe8,0x3c,0xfb,0x4a];
+
+        let aes = try! AES(key: key, iv:iv, blockMode: .OFB)
+        XCTAssertTrue(aes.blockMode == .OFB, "Invalid block mode")
+        let encrypted = try! aes.encrypt(plaintext, padding: nil)
+        XCTAssertEqual(encrypted, expected, "encryption failed")
+        let decrypted = try! aes.decrypt(encrypted, padding: nil)
+        XCTAssertEqual(decrypted, plaintext, "decryption failed")
+    }
+
+    func testAES_encrypt_ofb256() {
+        let key: [UInt8] = [0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4]
+        let iv: [UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
+        let plaintext: [UInt8] = [0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a]
+        let expected:[UInt8] = [0xdc,0x7e,0x84,0xbf,0xda,0x79,0x16,0x4b,0x7e,0xcd,0x84,0x86,0x98,0x5d,0x38,0x60];
+
+        let aes = try! AES(key: key, iv:iv, blockMode: .OFB)
+        XCTAssertTrue(aes.blockMode == .OFB, "Invalid block mode")
+        let encrypted = try! aes.encrypt(plaintext, padding: nil)
+        XCTAssertEqual(encrypted, expected, "encryption failed")
+        let decrypted = try! aes.decrypt(encrypted, padding: nil)
+        XCTAssertEqual(decrypted, plaintext, "decryption failed")
+    }
+
+    func testAES_encrypt_pcbc256() {
+        let key: [UInt8] = [0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4]
+        let iv: [UInt8] = [0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F]
+        let plaintext: [UInt8] = [0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a]
+        let expected:[UInt8] = [0xf5,0x8c,0x4c,0x04,0xd6,0xe5,0xf1,0xba,0x77,0x9e,0xab,0xfb,0x5f,0x7b,0xfb,0xd6];
+
+        let aes = try! AES(key: key, iv:iv, blockMode: .PCBC)
+        XCTAssertTrue(aes.blockMode == .PCBC, "Invalid block mode")
+        let encrypted = try! aes.encrypt(plaintext, padding: nil)
+        print(encrypted.toHexString())
+        XCTAssertEqual(encrypted, expected, "encryption failed")
+        let decrypted = try! aes.decrypt(encrypted, padding: nil)
+        XCTAssertEqual(decrypted, plaintext, "decryption failed")
+    }
+
     func testAES_encrypt_ctr() {
         let key:[UInt8] = [0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c];
         let iv:[UInt8] = [0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff]

+ 9 - 2
CryptoSwiftTests/ExtensionsTest.swift

@@ -91,7 +91,14 @@ final class ExtensionsTest: XCTestCase {
     }
 
     func test_String_encrypt_base64() {
-        let encrypted: String = try! "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345"))
-        XCTAssertEqual(encrypted, "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=")
+        let encryptedBase64 = try! "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345")).toBase64()
+        XCTAssertEqual(encryptedBase64, "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=")
     }
+
+    func test_String_decrypt_base64() {
+        let encryptedBase64 = "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs="
+        let decrypted = try! encryptedBase64.decryptBase64ToString(AES(key: "secret0key000000", iv: "0123456789012345"))
+        XCTAssertEqual(decrypted, "my secret string")
+    }
+
 }

+ 8 - 3
README.md

@@ -46,7 +46,9 @@ Good mood
 #####Cipher block mode
 - Electronic codebook ([ECB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29))
 - Cipher-block chaining ([CBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29))
+- Propagating Cipher Block Chaining ([PCBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29))
 - Cipher feedback ([CFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29))
+- Output Feedback ([OFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29))
 - Counter ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29))
 
 #####Data padding
@@ -205,11 +207,14 @@ let input: [UInt8] = [0,1,2,3,4,5,6,7,8,9]
 input.encrypt(AES(key: "secret0key000000", iv:"0123456789012345", blockMode: .CBC))
 ```
 
-Encrypt String to Base64 string result:
+Encrypt/Decrypt String to Base64 encoded string:
 
 ```swift
 // Encrypt string and get Base64 representation of result
-let base64: String = try! "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345"))
+let base64String = try! "my secret string".encrypt(AES(key: "secret0key000000", iv: "0123456789012345")).toBase64()
+
+// Decrypt Base64 encrypted message with helper function:
+let decrypted = try! encryptedBase64.decryptBase64ToString(AES(key: "secret0key000000", iv: "0123456789012345"))
 ```
 
 ...under the hood, this is [UInt8] converted to NSData converted to Base64 string representation:
@@ -241,7 +246,7 @@ AES without data padding
 
 ```swift
 let input: [UInt8] = [0,1,2,3,4,5,6,7,8,9]
-let encrypted: [UInt8] = try! AES(key: "secret0key000000", iv:"0123456789012345", blockMode: .CBC).encrypt(input)
+let encrypted: [UInt8] = try! AES(key: "secret0key000000", iv:"0123456789012345", blockMode: .CBC).encrypt(input, padding: nil)
 ```
 
 Using extensions

+ 20 - 6
Sources/CryptoSwift/AES.swift

@@ -125,7 +125,14 @@ final public class AES {
 
 
         let blocks = finalBytes.chunks(AES.blockSize)
-        return try blockMode.encryptBlocks(blocks, iv: self.iv, cipherOperation: encryptBlock)
+        let encryptGenerator = blockMode.encryptGenerator(iv, cipherOperation: encryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
+
+        var out = [UInt8]()
+        out.reserveCapacity(bytes.count)
+        for processedBlock in AnySequence<Array<UInt8>>({ encryptGenerator }) {
+            out.appendContentsOf(processedBlock)
+        }
+        return out
     }
 
     private func encryptBlock(block:[UInt8]) -> [UInt8]? {
@@ -198,13 +205,20 @@ final public class AES {
         }
         
         let blocks = bytes.chunks(AES.blockSize)
-        let out:[UInt8]
+        var out = [UInt8]()
+        out.reserveCapacity(bytes.count)
         switch (blockMode) {
-        case .CFB, .CTR:
-            // CFB, CTR uses encryptBlock to decrypt
-            out = try blockMode.decryptBlocks(blocks, iv: self.iv, cipherOperation: encryptBlock)
+        case .CFB, .OFB, .CTR:
+            // CFB, OFB, CTR uses encryptBlock to decrypt
+            let decryptGenerator = blockMode.decryptGenerator(iv, cipherOperation: encryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
+            for processedBlock in AnySequence<Array<UInt8>>({ decryptGenerator }) {
+                out.appendContentsOf(processedBlock)
+            }
         default:
-            out = try blockMode.decryptBlocks(blocks, iv: self.iv, cipherOperation: decryptBlock)
+            let decryptGenerator = blockMode.decryptGenerator(iv, cipherOperation: decryptBlock, inputGenerator: AnyGenerator<Array<UInt8>>(blocks.generate()))
+            for processedBlock in AnySequence<Array<UInt8>>({ decryptGenerator }) {
+                out.appendContentsOf(processedBlock)
+            }
         }
         
         if let padding = padding {

+ 2 - 2
Sources/CryptoSwift/Array+Extension.swift

@@ -7,12 +7,12 @@
 //
 
 extension Array {
-    
+
     /** split in chunks with given chunk size */
     func chunks(chunksize:Int) -> [Array<Element>] {
         var words = [[Element]]()
         words.reserveCapacity(self.count / chunksize)        
-        for var idx = chunksize; idx <= self.count; idx = idx + chunksize {
+        for idx in chunksize.stride(through: self.count, by: chunksize) {
             let word = Array(self[idx - chunksize..<idx]) // this is slow for large table
             words.append(word)
         }

+ 20 - 0
Sources/CryptoSwift/BlockMode/BlockModeGenerator.swift

@@ -0,0 +1,20 @@
+//
+//  BlockModeGenerator.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+
+// I have no better name for that
+
+enum BlockError: ErrorType {
+    case MissingInitializationVector
+}
+
+typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
+
+protocol BlockModeGenerator: GeneratorType {
+    var options: BlockModeOptions { get }
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>)
+}

+ 15 - 0
Sources/CryptoSwift/BlockMode/BlockModeOptions.swift

@@ -0,0 +1,15 @@
+//
+//  BlockModeOptions.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+
+struct BlockModeOptions: OptionSetType {
+    let rawValue: Int
+
+    static let None = BlockModeOptions(rawValue: 0)
+    static let InitializationVectorRequired = BlockModeOptions(rawValue: 1)
+    static let PaddingRequired = BlockModeOptions(rawValue: 2)
+}

+ 66 - 0
Sources/CryptoSwift/BlockMode/CBC.swift

@@ -0,0 +1,66 @@
+//
+//  CBC.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+//  Cipher-block chaining (CBC)
+//
+
+struct CBCModeEncryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next(),
+              let encrypted = cipherOperation(block: xor(prevCiphertext ?? iv, plaintext))
+        else {
+            return nil
+        }
+
+        self.prevCiphertext = encrypted
+        return encrypted
+    }
+}
+
+struct CBCModeDecryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let ciphertext = inputGenerator.next(),
+              let decrypted = cipherOperation(block: ciphertext)
+        else {
+            return nil
+        }
+
+        let result = xor(prevCiphertext ?? iv, decrypted)
+        self.prevCiphertext = ciphertext
+        return result
+    }
+}

+ 66 - 0
Sources/CryptoSwift/BlockMode/CFB.swift

@@ -0,0 +1,66 @@
+//
+//  CFB.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+//  Cipher feedback (CFB)
+//
+
+struct CFBModeEncryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next(),
+            let ciphertext = cipherOperation(block: prevCiphertext ?? iv)
+            else {
+                return nil
+        }
+
+        self.prevCiphertext = xor(plaintext, ciphertext)
+        return self.prevCiphertext
+    }
+}
+
+struct CFBModeDecryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let ciphertext = inputGenerator.next(),
+            let decrypted = cipherOperation(block: self.prevCiphertext ?? iv)
+            else {
+                return nil
+        }
+
+        let result = xor(decrypted, ciphertext)
+        self.prevCiphertext = ciphertext
+        return result
+    }
+}

+ 80 - 0
Sources/CryptoSwift/BlockMode/CTR.swift

@@ -0,0 +1,80 @@
+//
+//  CTR.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+//  Counter (CTR)
+//
+
+struct CTRModeEncryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var counter: UInt = 0
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next() else {
+            return nil
+        }
+
+        let nonce = buildNonce(iv, counter: UInt64(counter))
+        counter = counter + 1
+        if let encrypted = cipherOperation(block: nonce) {
+            return xor(plaintext, encrypted)
+        }
+
+        return nil
+    }
+}
+
+struct CTRModeDecryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var counter: UInt = 0
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let ciphertext = inputGenerator.next() else {
+            return nil
+        }
+
+        let nonce = buildNonce(iv, counter: UInt64(counter))
+        counter = counter + 1
+
+        if let decrypted = cipherOperation(block: nonce) {
+            return xor(decrypted, ciphertext)
+        }
+
+        return nil
+    }
+}
+
+private func buildNonce(iv: [UInt8], counter: UInt64) -> [UInt8] {
+    let noncePartLen = AES.blockSize / 2
+    let noncePrefix = Array(iv[0..<noncePartLen])
+    let nonceSuffix = Array(iv[noncePartLen..<iv.count])
+    let c = UInt64.withBytes(nonceSuffix) + counter
+    return noncePrefix + arrayOfBytes(c)
+}

+ 94 - 0
Sources/CryptoSwift/BlockMode/CipherBlockMode.swift

@@ -0,0 +1,94 @@
+//
+//  CipherBlockMode.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+
+import Foundation
+
+public enum CipherBlockMode {
+    case ECB, CBC, PCBC, CFB, OFB, CTR
+
+    func encryptGenerator(iv: Array<UInt8>?, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) -> AnyGenerator<Array<UInt8>> {
+        switch (self) {
+        case CBC:
+            return AnyGenerator<Array<UInt8>>(CBCModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case CFB:
+            return AnyGenerator<Array<UInt8>>(CFBModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case OFB:
+            return AnyGenerator<Array<UInt8>>(OFBModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case CTR:
+            return AnyGenerator<Array<UInt8>>(CTRModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case PCBC:
+            return AnyGenerator<Array<UInt8>>(PCBCModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case ECB:
+            return AnyGenerator<Array<UInt8>>(ECBModeEncryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        }
+    }
+
+    func decryptGenerator(iv: Array<UInt8>?, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) -> AnyGenerator<Array<UInt8>> {
+        switch (self) {
+        case CBC:
+            return AnyGenerator<Array<UInt8>>(CBCModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case CFB:
+            return AnyGenerator<Array<UInt8>>(CFBModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case OFB:
+            return AnyGenerator<Array<UInt8>>(OFBModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case CTR:
+            return AnyGenerator<Array<UInt8>>(CTRModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case PCBC:
+            return AnyGenerator<Array<UInt8>>(PCBCModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        case ECB:
+            return AnyGenerator<Array<UInt8>>(ECBModeDecryptGenerator(iv: iv ?? [], cipherOperation: cipherOperation, inputGenerator: inputGenerator))
+        }
+    }
+
+    var options: BlockModeOptions {
+        switch (self) {
+        case .CBC:
+            return [.InitializationVectorRequired, .PaddingRequired]
+        case .CFB:
+            return .InitializationVectorRequired
+        case .CTR:
+            return .InitializationVectorRequired
+        case .ECB:
+            return .PaddingRequired
+        case .OFB:
+            return .InitializationVectorRequired
+        case .PCBC:
+            return [.InitializationVectorRequired, .PaddingRequired]
+        }
+    }
+
+    /**
+     Process input blocks with given block cipher mode. With fallback to plain mode.
+
+     - parameter blocks: cipher block size blocks
+     - parameter iv:     IV
+     - parameter cipher: single block encryption closure
+
+     - returns: encrypted bytes
+     */
+//    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
+//
+//        // if IV is not available, fallback to plain
+//        var finalBlockMode:CipherBlockMode = self
+//        if (iv == nil) {
+//            finalBlockMode = .ECB
+//        }
+//
+//        return try finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
+//    }
+//
+//    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
+//        // if IV is not available, fallback to plain
+//        var finalBlockMode:CipherBlockMode = self
+//        if (iv == nil) {
+//            finalBlockMode = .ECB
+//        }
+//
+//        return try finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
+//    }
+}

+ 37 - 0
Sources/CryptoSwift/BlockMode/ECB.swift

@@ -0,0 +1,37 @@
+//
+//  CipherBlockMode.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 27/12/14.
+//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
+//
+//  Electronic codebook (ECB)
+//
+
+struct ECBModeEncryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next(),
+              let encrypted = cipherOperation(block: plaintext)
+        else {
+            return nil
+        }
+
+        return encrypted
+    }
+}
+
+typealias ECBModeDecryptGenerator = ECBModeEncryptGenerator

+ 66 - 0
Sources/CryptoSwift/BlockMode/OFB.swift

@@ -0,0 +1,66 @@
+//
+//  OFB.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+// Output Feedback (OFB)
+//
+
+struct OFBModeEncryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next(),
+            let ciphertext = cipherOperation(block: prevCiphertext ?? iv)
+            else {
+                return nil
+        }
+
+        self.prevCiphertext = ciphertext
+        return xor(plaintext, ciphertext)
+    }
+}
+
+struct OFBModeDecryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let ciphertext = inputGenerator.next(),
+            let decrypted = cipherOperation(block: self.prevCiphertext ?? iv)
+            else {
+                return nil
+        }
+
+        let plaintext = xor(decrypted, ciphertext)
+        self.prevCiphertext = decrypted
+        return plaintext
+    }
+}

+ 66 - 0
Sources/CryptoSwift/BlockMode/PCBC.swift

@@ -0,0 +1,66 @@
+//
+//  PCBM.swift
+//  CryptoSwift
+//
+//  Created by Marcin Krzyzanowski on 08/03/16.
+//  Copyright © 2016 Marcin Krzyzanowski. All rights reserved.
+//
+//  Propagating Cipher Block Chaining (PCBC)
+//
+
+struct PCBCModeEncryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Array<UInt8>>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let plaintext = inputGenerator.next(),
+              let encrypted = cipherOperation(block: xor(prevCiphertext ?? iv, plaintext))
+        else {
+            return nil
+        }
+
+        self.prevCiphertext = xor(plaintext, encrypted)
+        return encrypted
+    }
+}
+
+struct PCBCModeDecryptGenerator: BlockModeGenerator {
+    typealias Element = Array<UInt8>
+    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
+
+    private let iv: Element
+    private let inputGenerator: AnyGenerator<Element>
+
+    private let cipherOperation: CipherOperationOnBlock
+    private var prevCiphertext: Element?
+
+    init(iv: Array<UInt8>, cipherOperation: CipherOperationOnBlock, inputGenerator: AnyGenerator<Element>) {
+        self.iv = iv
+        self.cipherOperation = cipherOperation
+        self.inputGenerator = inputGenerator
+    }
+
+    mutating func next() -> Element? {
+        guard let ciphertext = inputGenerator.next(),
+              let decrypted = cipherOperation(block: ciphertext)
+        else {
+            return nil
+        }
+
+        let plaintext = xor(prevCiphertext ?? iv, decrypted)
+        self.prevCiphertext = xor(plaintext, ciphertext)
+        return plaintext
+    }
+}

+ 1 - 10
Sources/CryptoSwift/BytesSequence.swift

@@ -6,15 +6,6 @@
 //  Copyright © 2015 Marcin Krzyzanowski. All rights reserved.
 //
 
-//TODO: func anyGenerator is renamed to AnyGenerator in Swift 2.2, until then it's just dirty hack for linux (because swift >= 2.2 is available for Linux)
-private func CS_AnyGenerator<Element>(body: () -> Element?) -> AnyGenerator<Element> {
- #if os(Linux)
-    return AnyGenerator(body: body)
- #else
-     return anyGenerator(body)
- #endif
-}
-
 struct BytesSequence: SequenceType {
     let chunkSize: Int
     let data: [UInt8]
@@ -23,7 +14,7 @@ struct BytesSequence: SequenceType {
         
         var offset:Int = 0
         
-        return CS_AnyGenerator {
+        return AnyGenerator {
             let end = min(self.chunkSize, self.data.count - offset)
             let result = self.data[offset..<offset + end]
             offset += result.count

+ 21 - 2
Sources/CryptoSwift/CSArrayType+Extensions.swift

@@ -17,11 +17,30 @@ extension Array: CSArrayType {
 }
 
 public extension CSArrayType where Generator.Element == UInt8 {
-    
     public func toHexString() -> String {
         return self.lazy.reduce("") { $0 + String(format:"%02x", $1) }
     }
-    
+
+    public func toBase64() -> String? {
+        guard let bytesArray = self as? [UInt8] else {
+            return nil
+        }
+
+        return NSData(bytes: bytesArray).base64EncodedStringWithOptions([])
+    }
+
+    public init(base64: String) {
+        self.init()
+
+        guard let decodedData = NSData(base64EncodedString: base64, options: []) else {
+            return
+        }
+
+        self.appendContentsOf(decodedData.arrayOfBytes())
+    }
+}
+
+public extension CSArrayType where Generator.Element == UInt8 {
     public func md5() -> [Generator.Element] {
         return Hash.md5(cs_arrayValue()).calculate()
     }

+ 0 - 240
Sources/CryptoSwift/CipherBlockMode.swift

@@ -1,240 +0,0 @@
-//
-//  CipherBlockMode.swift
-//  CryptoSwift
-//
-//  Created by Marcin Krzyzanowski on 27/12/14.
-//  Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
-//
-
-// I have no better name for that
-typealias CipherOperationOnBlock = (block: [UInt8]) -> [UInt8]?
-
-enum BlockError: ErrorType {
-    case MissingInitializationVector
-}
-
-struct BlockModeOptions: OptionSetType {
-    let rawValue: Int
-
-    static let None = BlockModeOptions(rawValue: 0)
-    static let InitializationVectorRequired = BlockModeOptions(rawValue: 1)
-    static let PaddingRequired = BlockModeOptions(rawValue: 2)
-}
-
-private protocol BlockMode {
-    var options: BlockModeOptions { get }
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8]
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8]
-}
-
-public enum CipherBlockMode {
-    case ECB, CBC, CFB, CTR
-    
-    private var mode:BlockMode {
-        switch (self) {
-        case CBC:
-            return CBCMode()
-        case CFB:
-            return CFBMode()
-        case ECB:
-            return ECBMode()
-        case CTR:
-            return CTRMode()
-        }
-    }
-
-    var options: BlockModeOptions { return mode.options }
-    
-    /**
-    Process input blocks with given block cipher mode. With fallback to plain mode.
-    
-    - parameter blocks: cipher block size blocks
-    - parameter iv:     IV
-    - parameter cipher: single block encryption closure
-    
-    - returns: encrypted bytes
-    */
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        
-        // if IV is not available, fallback to plain
-        var finalBlockMode:CipherBlockMode = self
-        if (iv == nil) {
-            finalBlockMode = .ECB
-        }
-        
-        return try finalBlockMode.mode.encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
-    }
-    
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        // if IV is not available, fallback to plain
-        var finalBlockMode:CipherBlockMode = self
-        if (iv == nil) {
-            finalBlockMode = .ECB
-        }
-
-        return try finalBlockMode.mode.decryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
-    }
-}
-
-/**
-Cipher-block chaining (CBC)
-*/
-private struct CBCMode: BlockMode {
-    let options: BlockModeOptions = [.InitializationVectorRequired, .PaddingRequired]
-    
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        precondition(blocks.count > 0)
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
-        
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        var prevCiphertext = iv // for the first time prevCiphertext = iv
-        for plaintext in blocks {
-            if let encrypted = cipherOperation(block: xor(prevCiphertext, plaintext)) {
-                out.appendContentsOf(encrypted)
-                prevCiphertext = encrypted
-            }
-        }
-        return out
-    }
-    
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        precondition(blocks.count > 0)
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
-
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        var prevCiphertext = iv // for the first time prevCiphertext = iv
-        for ciphertext in blocks {
-            if let decrypted = cipherOperation(block: ciphertext) { // decrypt
-                out.appendContentsOf(xor(prevCiphertext, decrypted)) //FIXME: b:
-            }
-            prevCiphertext = ciphertext
-        }
-        
-        return out
-    }
-}
-
-/**
-Cipher feedback (CFB)
-*/
-private struct CFBMode: BlockMode {
-    let options: BlockModeOptions = [.InitializationVectorRequired]
-
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
-        
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-
-        var lastCiphertext = iv
-        for plaintext in blocks {
-            if let ciphertext = cipherOperation(block: lastCiphertext) {
-                lastCiphertext = xor(plaintext, ciphertext)
-                out.appendContentsOf(lastCiphertext)
-            }
-        }
-        return out
-    }
-    
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
-        
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-
-        var lastCiphertext = iv
-        for ciphertext in blocks {
-            if let decrypted = cipherOperation(block: lastCiphertext) {
-                out.appendContentsOf(xor(decrypted, ciphertext))
-            }
-            lastCiphertext = ciphertext
-        }
-        
-        return out
-    }
-}
-
-
-/**
-Electronic codebook (ECB)
-*/
-private struct ECBMode: BlockMode {
-    let options: BlockModeOptions = [.PaddingRequired]
-
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8] {
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        for plaintext in blocks {
-            if let encrypted = cipherOperation(block: plaintext) {
-                out.appendContentsOf(encrypted)
-            }
-        }
-        return out
-    }
-    
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) -> [UInt8] {
-        return encryptBlocks(blocks, iv: iv, cipherOperation: cipherOperation)
-    }
-}
-
-/**
-Counter (CTR)
-*/
-private struct CTRMode: BlockMode {
-    let options = BlockModeOptions.InitializationVectorRequired
-
-    private func buildNonce(iv: [UInt8], counter: UInt64) -> [UInt8] {
-        let noncePartLen = AES.blockSize / 2
-        let noncePrefix = Array(iv[0..<noncePartLen])
-        let nonceSuffix = Array(iv[noncePartLen..<iv.count])
-        let c = UInt64.withBytes(nonceSuffix) + counter
-        return noncePrefix + arrayOfBytes(c)
-    }
-    
-    func encryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        //var counter:UInt = 17940646550795321087
-        
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
-
-        var counter:UInt = 0
-        var out:[UInt8] = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        for plaintext in blocks {
-            let nonce = buildNonce(iv, counter: UInt64(counter++))
-            if let encrypted = cipherOperation(block: nonce) {
-                out.appendContentsOf(xor(plaintext, encrypted))
-            }
-        }
-        return out
-    }
-    
-    func decryptBlocks(blocks:[[UInt8]], iv:[UInt8]?, cipherOperation:CipherOperationOnBlock) throws -> [UInt8] {
-        guard let iv = iv else {
-            throw BlockError.MissingInitializationVector
-        }
-        
-        var counter:UInt = 0
-        var out = [UInt8]()
-        out.reserveCapacity(blocks.count * blocks[blocks.startIndex].count)
-        for ciphertext in blocks {
-            let nonce = buildNonce(iv, counter: UInt64(counter++))
-            if let decrypted = cipherOperation(block: nonce) {
-                out.appendContentsOf(xor(decrypted, ciphertext))
-            }
-        }
-        return out
-    }
-
-}

+ 20 - 7
Sources/CryptoSwift/Foundation/String+FoundationExtension.swift

@@ -10,14 +10,27 @@ import Foundation
 
 extension String {
 
-    /// Return Base64 representation
-    public func encrypt(cipher: Cipher) throws -> String {
-        let encrypted = try self.utf8.lazy.map({ $0 as UInt8 }).encrypt(cipher)
-        return NSData(bytes: encrypted).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
+    /// Return Base64 back to String
+    public func decryptBase64ToString(cipher: Cipher) throws -> String {
+        guard let decodedData = NSData(base64EncodedString: self, options: []) else {
+            throw CipherError.Decrypt
+        }
+
+        let decrypted = try decodedData.decrypt(cipher)
+
+        if let decryptedString = String(data: decrypted, encoding: NSUTF8StringEncoding) {
+            return decryptedString
+        }
+
+        throw CipherError.Decrypt
     }
 
-    public func decrypt(cipher: Cipher) throws -> String {
-        let decrypted = try self.utf8.lazy.map({ $0 as UInt8 }).decrypt(cipher)
-        return NSData(bytes: decrypted).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
+    public func decryptBase64(cipher: Cipher) throws -> [UInt8] {
+        guard let decodedData = NSData(base64EncodedString: self, options: []) else {
+            throw CipherError.Decrypt
+        }
+
+        return try decodedData.decrypt(cipher).arrayOfBytes()
     }
+
 }

+ 2 - 2
Sources/CryptoSwift/HashProtocol.swift

@@ -26,8 +26,8 @@ extension HashProtocol {
         var counter = 0
         
         while msgLength % len != (len - 8) {
-            counter++
-            msgLength++
+            counter += 1
+            msgLength += 1
         }
 
         tmpMessage += Array<UInt8>(count: counter, repeatedValue: 0)

+ 5 - 1
Sources/CryptoSwift/PKCS7.swift

@@ -37,7 +37,11 @@ public struct PKCS7: Padding {
     }
 
     public func remove(bytes: [UInt8], blockSize:Int?) -> [UInt8] {
-        let lastByte = bytes.last!
+        assert(bytes.count > 0, "Need bytes to remove padding")
+        guard bytes.count > 0, let lastByte = bytes.last else {
+            return bytes
+        }
+
         let padding = Int(lastByte) // last byte
         let finalLength = bytes.count - padding
 

+ 11 - 6
Sources/CryptoSwift/Rabbit.swift

@@ -64,12 +64,12 @@ final public class Rabbit {
         
         // Key divided into 8 subkeys
         var k = [UInt32](count: 8, repeatedValue: 0)
-        for var j = 0; j < 8; j++ {
+        for j in 0..<8 {
             k[j] = UInt32(key[Rabbit.blockSize - (2*j + 1)]) | (UInt32(key[Rabbit.blockSize - (2*j + 2)]) << 8)
         }
         
         // Initialize state and counter variables from subkeys
-        for var j = 0; j < 8; j++ {
+        for j in 0..<8 {
             if j % 2 == 0 {
                 x[j] = (k[(j+1) % 8] << 16) | k[j]
                 c[j] = (k[(j+4) % 8] << 16) | k[(j+5) % 8]
@@ -86,7 +86,7 @@ final public class Rabbit {
         nextState()
         
         // Reinitialize counter variables
-        for var j = 0; j < 8; j++ {
+        for j in 0..<8 {
             c[j] = c[j] ^ x[(j+4) % 8]
         }
         
@@ -123,7 +123,7 @@ final public class Rabbit {
     private func nextState() {
         // Before an iteration the counters are incremented
         var carry = p7
-        for var j = 0; j < 8; j++ {
+        for j in 0..<8 {
             let prev = c[j]
             c[j] = prev &+ a[j] &+ carry
             carry = prev > c[j] ? 1 : 0 // detect overflow
@@ -163,7 +163,7 @@ final public class Rabbit {
         output16[0] = UInt16(truncatingBitPattern: x[6] >> 16) ^ UInt16(truncatingBitPattern: x[1])
         
         var output8 = [UInt8](count: Rabbit.blockSize, repeatedValue: 0)
-        for var j = 0; j < output16.count; j++ {
+        for j in 0..<output16.count {
             output8[j * 2] = UInt8(truncatingBitPattern: output16[j] >> 8)
             output8[j * 2 + 1] = UInt8(truncatingBitPattern: output16[j])
         }
@@ -176,13 +176,18 @@ final public class Rabbit {
         
         var result = [UInt8](count: bytes.count, repeatedValue: 0)
         var output = nextOutput()
-        for var byteIdx = 0, outputIdx = 0; byteIdx < bytes.count; byteIdx++, outputIdx++ {
+        var byteIdx = 0
+        var outputIdx = 0
+        while byteIdx < bytes.count {
             if (outputIdx == Rabbit.blockSize) {
                 output = nextOutput()
                 outputIdx = 0
             }
             
             result[byteIdx] = bytes[byteIdx] ^ output[outputIdx]
+
+            byteIdx += 1
+            outputIdx += 1
         }
         return result
     }

+ 7 - 2
Sources/CryptoSwift/SHA2.swift

@@ -273,8 +273,13 @@ final class SHA2 : HashProtocol {
         result.reserveCapacity(hh.count / 4)
         variant.resultingArray(hh).forEach {
             let item = $0.bigEndian
-            result += [UInt8(item & 0xff), UInt8((item >> 8) & 0xff), UInt8((item >> 16) & 0xff), UInt8((item >> 24) & 0xff),
-                       UInt8((item >> 32) & 0xff),UInt8((item >> 40) & 0xff), UInt8((item >> 48) & 0xff), UInt8((item >> 56) & 0xff)]
+            var partialResult = [UInt8]()
+            partialResult.reserveCapacity(8)
+            for i in 0..<8 {
+                let shift = UInt64(8 * i)
+                partialResult.append(UInt8((item >> shift) & 0xff))
+            }
+            result += partialResult
         }
         return result
     }