Skip to content

Commit 43bd963

Browse files
committed
Make ChaCha20 inherit from Salsa20.
1 parent dc03424 commit 43bd963

File tree

1 file changed

+4
-175
lines changed

1 file changed

+4
-175
lines changed

Sources/CryptoSwift/ChaCha20.swift

Lines changed: 4 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// CryptoSwift
33
//
44
// Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
5-
// Copyright (C) 2019 Roger Miret <roger.miret@gmail.com>
5+
// Copyright (C) 2019 Roger Miret Giné <roger.miret@gmail.com>
66
// This software is provided 'as-is', without any express or implied warranty.
77
//
88
// In no event will the authors be held liable for any damages arising from the use of this software.
@@ -17,42 +17,9 @@
1717
// https://tools.ietf.org/html/rfc7539
1818
//
1919

20-
public final class ChaCha20: BlockCipher {
21-
public enum Error: Swift.Error {
22-
case invalidKeyOrInitializationVector
23-
case notSupported
24-
}
25-
26-
public static let blockSize = 64 // 512 / 8
27-
public let keySize: Int
28-
29-
fileprivate let key: Key
30-
fileprivate var counter: Array<UInt8>
31-
32-
public init(key: Array<UInt8>, iv nonce: Array<UInt8>) throws {
33-
precondition(nonce.count == 12 || nonce.count == 8)
20+
public final class ChaCha20: Salsa20 {
3421

35-
if key.count != 32 {
36-
throw Error.invalidKeyOrInitializationVector
37-
}
38-
39-
self.key = Key(bytes: key)
40-
keySize = self.key.count
41-
42-
if nonce.count == 8 {
43-
counter = [0, 0, 0, 0, 0, 0, 0, 0] + nonce
44-
} else {
45-
counter = [0, 0, 0, 0] + nonce
46-
}
47-
48-
assert(counter.count == 16)
49-
}
50-
51-
fileprivate func rotl(_ a: UInt32, _ b: Int) -> UInt32 {
52-
return (a << b) | (a >> (32 - b))
53-
}
54-
55-
fileprivate func qr(_ a: inout UInt32, _ b: inout UInt32, _ c: inout UInt32, _ d: inout UInt32) {
22+
override internal func qr(_ a: inout UInt32, _ b: inout UInt32, _ c: inout UInt32, _ d: inout UInt32) {
5623
a = a &+ b
5724
d ^= a
5825
d = rotl(d, 16)
@@ -71,7 +38,7 @@ public final class ChaCha20: BlockCipher {
7138
}
7239

7340
/// https://tools.ietf.org/html/rfc7539#section-2.3.
74-
fileprivate func core(block: inout Array<UInt8>, counter: Array<UInt8>, key: Array<UInt8>) {
41+
override internal func core(block: inout Array<UInt8>, counter: Array<UInt8>, key: Array<UInt8>) {
7542
precondition(block.count == ChaCha20.blockSize)
7643
precondition(counter.count == 16)
7744
precondition(key.count == 32)
@@ -143,142 +110,4 @@ public final class ChaCha20: BlockCipher {
143110
block.replaceSubrange(56..<60, with: x14.bigEndian.bytes())
144111
block.replaceSubrange(60..<64, with: x15.bigEndian.bytes())
145112
}
146-
147-
// XORKeyStream
148-
func process(bytes: ArraySlice<UInt8>, counter: inout Array<UInt8>, key: Array<UInt8>) -> Array<UInt8> {
149-
precondition(counter.count == 16)
150-
precondition(key.count == 32)
151-
152-
var block = Array<UInt8>(repeating: 0, count: ChaCha20.blockSize)
153-
var bytesSlice = bytes
154-
var out = Array<UInt8>(reserveCapacity: bytesSlice.count)
155-
156-
while bytesSlice.count >= ChaCha20.blockSize {
157-
core(block: &block, counter: counter, key: key)
158-
for (i, x) in block.enumerated() {
159-
out.append(bytesSlice[bytesSlice.startIndex + i] ^ x)
160-
}
161-
var u: UInt32 = 1
162-
for i in 0..<4 {
163-
u += UInt32(counter[i])
164-
counter[i] = UInt8(u & 0xff)
165-
u >>= 8
166-
}
167-
bytesSlice = bytesSlice[bytesSlice.startIndex + ChaCha20.blockSize..<bytesSlice.endIndex]
168-
}
169-
170-
if bytesSlice.count > 0 {
171-
core(block: &block, counter: counter, key: key)
172-
for (i, v) in bytesSlice.enumerated() {
173-
out.append(v ^ block[i])
174-
}
175-
}
176-
return out
177-
}
178-
}
179-
180-
// MARK: Cipher
181-
182-
extension ChaCha20: Cipher {
183-
public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
184-
return process(bytes: bytes, counter: &counter, key: Array(key))
185-
}
186-
187-
public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
188-
return try encrypt(bytes)
189-
}
190-
}
191-
192-
// MARK: Encryptor
193-
194-
extension ChaCha20 {
195-
public struct ChaChaEncryptor: Cryptor, Updatable {
196-
private var accumulated = Array<UInt8>()
197-
private let chacha: ChaCha20
198-
199-
init(chacha: ChaCha20) {
200-
self.chacha = chacha
201-
}
202-
203-
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = false) throws -> Array<UInt8> {
204-
accumulated += bytes
205-
206-
var encrypted = Array<UInt8>()
207-
encrypted.reserveCapacity(accumulated.count)
208-
for chunk in accumulated.batched(by: ChaCha20.blockSize) {
209-
if isLast || accumulated.count >= ChaCha20.blockSize {
210-
encrypted += try chacha.encrypt(chunk)
211-
accumulated.removeFirst(chunk.count) // TODO: improve performance
212-
}
213-
}
214-
return encrypted
215-
}
216-
217-
public func seek(to: Int) throws {
218-
throw Error.notSupported
219-
}
220-
}
221-
}
222-
223-
// MARK: Decryptor
224-
225-
extension ChaCha20 {
226-
public struct ChaChaDecryptor: Cryptor, Updatable {
227-
private var accumulated = Array<UInt8>()
228-
229-
private var offset: Int = 0
230-
private var offsetToRemove: Int = 0
231-
private let chacha: ChaCha20
232-
233-
init(chacha: ChaCha20) {
234-
self.chacha = chacha
235-
}
236-
237-
public mutating func update(withBytes bytes: ArraySlice<UInt8>, isLast: Bool = true) throws -> Array<UInt8> {
238-
// prepend "offset" number of bytes at the beginning
239-
if offset > 0 {
240-
accumulated += Array<UInt8>(repeating: 0, count: offset) + bytes
241-
offsetToRemove = offset
242-
offset = 0
243-
} else {
244-
accumulated += bytes
245-
}
246-
247-
var plaintext = Array<UInt8>()
248-
plaintext.reserveCapacity(accumulated.count)
249-
for chunk in accumulated.batched(by: ChaCha20.blockSize) {
250-
if isLast || accumulated.count >= ChaCha20.blockSize {
251-
plaintext += try chacha.decrypt(chunk)
252-
253-
// remove "offset" from the beginning of first chunk
254-
if offsetToRemove > 0 {
255-
plaintext.removeFirst(offsetToRemove) // TODO: improve performance
256-
offsetToRemove = 0
257-
}
258-
259-
accumulated.removeFirst(chunk.count)
260-
}
261-
}
262-
263-
return plaintext
264-
}
265-
266-
public func seek(to: Int) throws {
267-
throw Error.notSupported
268-
}
269-
}
270-
}
271-
272-
// MARK: Cryptors
273-
274-
extension ChaCha20: Cryptors {
275-
//TODO: Use BlockEncryptor/BlockDecryptor
276-
277-
public func makeEncryptor() -> Cryptor & Updatable {
278-
return ChaCha20.ChaChaEncryptor(chacha: self)
279-
}
280-
281-
public func makeDecryptor() -> Cryptor & Updatable {
282-
return ChaCha20.ChaChaDecryptor(chacha: self)
283-
}
284113
}

0 commit comments

Comments
 (0)