ChaCha20.swift 4.9 KB

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