ChaCha20.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. public class ChaCha20 {
  10. private let blockSizeBytes = 512 / 8
  11. private let stateSize = 16
  12. private var context:Context?
  13. private class Context {
  14. var input:[UInt32] = [UInt32](count: 16, repeatedValue: 0)
  15. deinit {
  16. for (var i = 0; i < input.count; i++) {
  17. input[i] = 0x00;
  18. }
  19. }
  20. }
  21. init?(key:NSData, iv:NSData) {
  22. if let c = contextSetup(iv: iv, key: key) {
  23. context = c
  24. } else {
  25. return nil
  26. }
  27. }
  28. func encrypt(message:NSData) -> NSData? {
  29. if (context == nil) {
  30. return nil
  31. }
  32. if let output = encryptBytes(message.bytes()) {
  33. return NSData.withBytes(output)
  34. }
  35. return nil
  36. }
  37. func decrypt(message:NSData) -> NSData? {
  38. return encrypt(message)
  39. }
  40. private func wordToByte(input:[UInt32] /* 64 */) -> [UInt8]? /* 16 */ {
  41. if (input.count != stateSize) {
  42. return nil;
  43. }
  44. var x = input
  45. var i = 10
  46. while (i > 0) {
  47. quarterround(&x[0], &x[4], &x[8], &x[12])
  48. quarterround(&x[1], &x[5], &x[9], &x[13])
  49. quarterround(&x[2], &x[6], &x[10], &x[14])
  50. quarterround(&x[3], &x[7], &x[11], &x[15])
  51. quarterround(&x[0], &x[5], &x[10], &x[15])
  52. quarterround(&x[1], &x[6], &x[11], &x[12])
  53. quarterround(&x[2], &x[7], &x[8], &x[13])
  54. quarterround(&x[3], &x[4], &x[9], &x[14])
  55. i -= 2
  56. }
  57. var output = [UInt8]()
  58. for i in 0..<16 {
  59. x[i] = x[i] &+ input[i]
  60. output += x[i].bytes().reverse()
  61. }
  62. return output;
  63. }
  64. private func contextSetup(# iv:NSData, key:NSData) -> Context? {
  65. return contextSetup(iv: iv.bytes(), key: key.bytes())
  66. }
  67. private func contextSetup(# iv:[UInt8], key:[UInt8]) -> Context? {
  68. var ctx = Context()
  69. let kbits = key.count * 8
  70. if (kbits != 128 && kbits != 256) {
  71. return nil
  72. }
  73. // 4 - 8
  74. for (var i = 0; i < 4; i++) {
  75. let start = i * 4
  76. ctx.input[i + 4] = UInt32.withBytes(key[start..<(start + 4)]).bigEndian
  77. }
  78. var addPos = 0;
  79. switch (kbits) {
  80. case 256:
  81. addPos += 16
  82. // sigma
  83. ctx.input[0] = 0x61707865 //apxe
  84. ctx.input[1] = 0x3320646e //3 dn
  85. ctx.input[2] = 0x79622d32 //yb-2
  86. ctx.input[3] = 0x6b206574 //k et
  87. default:
  88. // tau
  89. ctx.input[0] = 0x61707865 //apxe
  90. ctx.input[1] = 0x3620646e //6 dn
  91. ctx.input[2] = 0x79622d31 //yb-1
  92. ctx.input[3] = 0x6b206574 //k et
  93. break;
  94. }
  95. // 8 - 11
  96. for (var i = 0; i < 4; i++) {
  97. let start = addPos + (i*4)
  98. ctx.input[i + 8] = UInt32.withBytes(key[start..<(start + 4)]).bigEndian
  99. }
  100. // iv
  101. ctx.input[12] = 0
  102. ctx.input[13] = 0
  103. ctx.input[14] = UInt32.withBytes(iv[0..<4]).bigEndian
  104. ctx.input[15] = UInt32.withBytes(iv[4..<8]).bigEndian
  105. return ctx
  106. }
  107. private func encryptBytes(message:[UInt8]) -> [UInt8]? {
  108. if let ctx = context {
  109. var c:[UInt8] = [UInt8](count: message.count, repeatedValue: 0)
  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 <= blockSizeBytes) {
  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 < blockSizeBytes; i++) {
  127. c[i + cPos] = message[i + mPos] ^ output[i]
  128. }
  129. bytes -= blockSizeBytes
  130. cPos += blockSizeBytes
  131. mPos += blockSizeBytes
  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. }