ChaCha20.swift 4.6 KB

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