ChaCha20.swift 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. //
  2. // ChaCha20.swift
  3. // CryptoSwift
  4. //
  5. // Created by Marcin Krzyzanowski on 25/08/14.
  6. // Copyright (c) 2014 Marcin Krzyzanowski. All rights reserved.
  7. //
  8. import Foundation
  9. class ChaCha20 {
  10. private let stateSize = 16
  11. private var context:Context?
  12. private class Context {
  13. var input:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
  14. deinit {
  15. for (var i = 0; i < input.count; i++) {
  16. input[i] = 0x00;
  17. }
  18. }
  19. }
  20. init(key:NSData, iv:NSData) {
  21. if let c = contextSetup(iv: iv, key: key) {
  22. context = c
  23. }
  24. }
  25. func encrypt(message:NSData) -> NSData? {
  26. if (context == nil) {
  27. return nil
  28. }
  29. if let output = encryptBytes(message.bytes()) {
  30. return NSData(bytes: output, length: output.count)
  31. }
  32. return nil
  33. }
  34. func decrypt(message:NSData) -> NSData? {
  35. return encrypt(message)
  36. }
  37. private func wordToByte(input:[UInt32] /* 64 */) -> [Byte]? /* 16 */ {
  38. if (input.count != stateSize) {
  39. return nil;
  40. }
  41. var x = input
  42. var i = 10
  43. while (i > 0) {
  44. quarterround(&x[0], &x[4], &x[8], &x[12])
  45. quarterround(&x[1], &x[5], &x[9], &x[13])
  46. quarterround(&x[2], &x[6], &x[10], &x[14])
  47. quarterround(&x[3], &x[7], &x[11], &x[15])
  48. quarterround(&x[0], &x[5], &x[10], &x[15])
  49. quarterround(&x[1], &x[6], &x[11], &x[12])
  50. quarterround(&x[2], &x[7], &x[8], &x[13])
  51. quarterround(&x[3], &x[4], &x[9], &x[14])
  52. i -= 2
  53. }
  54. var output = [Byte]()
  55. for i in 0..<16 {
  56. x[i] = x[i] &+ input[i]
  57. output += x[i].bytes().reverse()
  58. }
  59. return output;
  60. }
  61. private func contextSetup(# iv:NSData, key:NSData) -> Context? {
  62. return contextSetup(iv: iv.bytes(), key: key.bytes())
  63. }
  64. private func contextSetup(# iv:[Byte], key:[Byte]) -> Context? {
  65. var ctx = Context()
  66. let kbits = key.count * 8
  67. if (kbits != 128 && kbits != 256) {
  68. return nil
  69. }
  70. // 4 - 8
  71. for (var i = 0; i < 4; i++) {
  72. let start = i * 4
  73. ctx.input[i + 4] = UInt32.withBytes(key[start..<(start + 4)]).bigEndian
  74. }
  75. var addPos = 0;
  76. switch (kbits) {
  77. case 256:
  78. addPos += 16
  79. // sigma
  80. ctx.input[0] = 0x61707865 //apxe
  81. ctx.input[1] = 0x3320646e //3 dn
  82. ctx.input[2] = 0x79622d32 //yb-2
  83. ctx.input[3] = 0x6b206574 //k et
  84. default:
  85. // tau
  86. ctx.input[0] = 0x61707865 //apxe
  87. ctx.input[1] = 0x3620646e //6 dn
  88. ctx.input[2] = 0x79622d31 //yb-1
  89. ctx.input[3] = 0x6b206574 //k et
  90. break;
  91. }
  92. // 8 - 11
  93. for (var i = 0; i < 4; i++) {
  94. let start = addPos + (i*4)
  95. ctx.input[i + 8] = UInt32.withBytes(key[start..<(start + 4)]).bigEndian
  96. }
  97. // iv
  98. ctx.input[12] = 0
  99. ctx.input[13] = 0
  100. ctx.input[14] = UInt32.withBytes(iv[0..<4]).bigEndian
  101. ctx.input[15] = UInt32.withBytes(iv[4..<8]).bigEndian
  102. return ctx
  103. }
  104. private func encryptBytes(message:[Byte]) -> [Byte]? {
  105. if let ctx = context {
  106. var c:[Byte] = [Byte](count: message.count, repeatedValue: 0)
  107. let blockSize = 64
  108. var cPos:Int = 0
  109. var mPos:Int = 0
  110. var bytes = message.count
  111. while (true) {
  112. if let output = wordToByte(ctx.input) {
  113. ctx.input[12] = ctx.input[12] &+ 1
  114. if (ctx.input[12] == 0) {
  115. ctx.input[13] = ctx.input[13] &+ 1
  116. /* stopping at 2^70 bytes per nonce is user's responsibility */
  117. }
  118. if (bytes <= blockSize) {
  119. for (var i = 0; i < bytes; i++) {
  120. c[i + cPos] = message[i + mPos] ^ output[i]
  121. }
  122. return c
  123. }
  124. for (var i = 0; i < blockSize; i++) {
  125. c[i + cPos] = message[i + mPos] ^ output[i]
  126. }
  127. bytes -= blockSize
  128. cPos += blockSize
  129. mPos += blockSize
  130. }
  131. }
  132. }
  133. return nil;
  134. }
  135. private func quarterround(inout a:UInt32, inout _ b:UInt32, inout _ c:UInt32, inout _ d:UInt32) {
  136. a = a &+ b
  137. d = rotateLeft((d ^ a), 16)
  138. c = c &+ d
  139. b = rotateLeft((b ^ c), 12);
  140. a = a &+ b
  141. d = rotateLeft((d ^ a), 8);
  142. c = c &+ d
  143. b = rotateLeft((b ^ c), 7);
  144. }
  145. }