|
|
@@ -13,12 +13,12 @@ final public class ChaCha20: BlockCipher {
|
|
|
case invalidKeyOrInitializationVector
|
|
|
}
|
|
|
|
|
|
- static let blockSize = 64 // 512 / 8
|
|
|
+ public static let blockSize = 64 // 512 / 8
|
|
|
private let stateSize = 16
|
|
|
private var context:Context?
|
|
|
|
|
|
final private class Context {
|
|
|
- var input:Array<UInt32> = Array<UInt32>(repeating: 0, count: 16)
|
|
|
+ var input = Array<UInt32>(repeating: 0, count: 16)
|
|
|
|
|
|
deinit {
|
|
|
for i in 0..<input.count {
|
|
|
@@ -76,20 +76,19 @@ final public class ChaCha20: BlockCipher {
|
|
|
|
|
|
var addPos = 0;
|
|
|
switch (kbits) {
|
|
|
- case 256:
|
|
|
- addPos += 16
|
|
|
- // sigma
|
|
|
- ctx.input[0] = 0x61707865 //apxe
|
|
|
- ctx.input[1] = 0x3320646e //3 dn
|
|
|
- ctx.input[2] = 0x79622d32 //yb-2
|
|
|
- ctx.input[3] = 0x6b206574 //k et
|
|
|
- default:
|
|
|
- // tau
|
|
|
- ctx.input[0] = 0x61707865 //apxe
|
|
|
- ctx.input[1] = 0x3620646e //6 dn
|
|
|
- ctx.input[2] = 0x79622d31 //yb-1
|
|
|
- ctx.input[3] = 0x6b206574 //k et
|
|
|
- break;
|
|
|
+ case 256:
|
|
|
+ addPos += 16
|
|
|
+ // sigma
|
|
|
+ ctx.input[0] = 0x61707865 //apxe
|
|
|
+ ctx.input[1] = 0x3320646e //3 dn
|
|
|
+ ctx.input[2] = 0x79622d32 //yb-2
|
|
|
+ ctx.input[3] = 0x6b206574 //k et
|
|
|
+ default:
|
|
|
+ // tau
|
|
|
+ ctx.input[0] = 0x61707865 //apxe
|
|
|
+ ctx.input[1] = 0x3620646e //6 dn
|
|
|
+ ctx.input[2] = 0x79622d31 //yb-1
|
|
|
+ ctx.input[3] = 0x6b206574 //k et
|
|
|
}
|
|
|
|
|
|
// 8 - 11
|
|
|
@@ -115,7 +114,7 @@ final public class ChaCha20: BlockCipher {
|
|
|
throw Error.missingContext
|
|
|
}
|
|
|
|
|
|
- var c:Array<UInt8> = Array<UInt8>(repeating: 0, count: message.count)
|
|
|
+ var c = Array<UInt8>(repeating: 0, count: message.count)
|
|
|
|
|
|
var cPos:Int = 0
|
|
|
var mPos:Int = 0
|
|
|
@@ -159,6 +158,89 @@ final public class ChaCha20: BlockCipher {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// MARK: Encryptor
|
|
|
+extension ChaCha20 {
|
|
|
+ public struct Encryptor: UpdatableCryptor {
|
|
|
+ private var accumulated = Array<UInt8>()
|
|
|
+ private let chacha: ChaCha20
|
|
|
+
|
|
|
+ init(chacha: ChaCha20) {
|
|
|
+ self.chacha = chacha
|
|
|
+ }
|
|
|
+
|
|
|
+ mutating public func update(withBytes bytes:Array<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
|
|
|
+ self.accumulated += bytes
|
|
|
+
|
|
|
+ var encrypted = Array<UInt8>()
|
|
|
+ encrypted.reserveCapacity(self.accumulated.count)
|
|
|
+ for chunk in self.accumulated.chunks(size: ChaCha20.blockSize) {
|
|
|
+ if (isLast || self.accumulated.count >= ChaCha20.blockSize) {
|
|
|
+ encrypted += try chacha.encrypt(chunk)
|
|
|
+ self.accumulated.removeFirst(chunk.count)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return encrypted
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// MARK: Decryptor
|
|
|
+extension ChaCha20 {
|
|
|
+ public struct Decryptor: UpdatableCryptor {
|
|
|
+ private var accumulated = Array<UInt8>()
|
|
|
+
|
|
|
+ private var offset: Int = 0
|
|
|
+ private var offsetToRemove: Int = 0
|
|
|
+ private let chacha: ChaCha20
|
|
|
+
|
|
|
+ init(chacha: ChaCha20) {
|
|
|
+ self.chacha = chacha
|
|
|
+ }
|
|
|
+
|
|
|
+ mutating public func update(withBytes bytes:Array<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
|
|
|
+ // prepend "offset" number of bytes at the begining
|
|
|
+ if self.offset > 0 {
|
|
|
+ self.accumulated += Array<UInt8>(repeating: 0, count: offset) + bytes
|
|
|
+ self.offsetToRemove = offset
|
|
|
+ self.offset = 0
|
|
|
+ } else {
|
|
|
+ self.accumulated += bytes
|
|
|
+ }
|
|
|
+
|
|
|
+ var plaintext = Array<UInt8>()
|
|
|
+ plaintext.reserveCapacity(self.accumulated.count)
|
|
|
+ for chunk in self.accumulated.chunks(size: ChaCha20.blockSize) {
|
|
|
+ if (isLast || self.accumulated.count >= ChaCha20.blockSize) {
|
|
|
+ plaintext += try chacha.decrypt(chunk)
|
|
|
+
|
|
|
+ // remove "offset" from the beginning of first chunk
|
|
|
+ if self.offsetToRemove > 0 {
|
|
|
+ plaintext.removeFirst(self.offsetToRemove);
|
|
|
+ self.offsetToRemove = 0
|
|
|
+ }
|
|
|
+
|
|
|
+ self.accumulated.removeFirst(chunk.count)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return plaintext
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// MARK: Cryptors
|
|
|
+extension ChaCha20: Cryptors {
|
|
|
+
|
|
|
+ public func makeEncryptor() -> ChaCha20.Encryptor {
|
|
|
+ return Encryptor(chacha: self)
|
|
|
+ }
|
|
|
+
|
|
|
+ public func makeDecryptor() -> ChaCha20.Decryptor {
|
|
|
+ return Decryptor(chacha: self)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// MARK: Cipher
|
|
|
extension ChaCha20: Cipher {
|
|
|
public func encrypt(_ bytes:Array<UInt8>) throws -> Array<UInt8> {
|