You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cipher.rb 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. module CryptCheck
  2. module Tls
  3. class Cipher
  4. TYPES = {
  5. md5: %w(MD5),
  6. sha1: %w(SHA),
  7. sha256: %w(SHA256),
  8. sha384: %w(SHA384),
  9. poly1305: %w(POLY1305),
  10. psk: %w(PSK),
  11. srp: %w(SRP),
  12. anonymous: %w(ADH AECDH),
  13. dss: %w(DSS),
  14. rsa: %w(RSA),
  15. ecdsa: %w(ECDSA),
  16. dh: %w(DH ADH),
  17. ecdh: %w(ECDH AECDH),
  18. dhe: %w(DHE EDH ADH),
  19. ecdhe: %w(ECDHE AECDH),
  20. null: %w(NULL),
  21. export: %w(EXP),
  22. rc2: %w(RC2),
  23. rc4: %w(RC4),
  24. des: %w(DES-CBC),
  25. des3: %w(3DES DES-CBC3),
  26. aes: %w(AES(128|256) AES-(128|256)),
  27. camellia: %w(CAMELLIA(128|256)),
  28. seed: %w(SEED),
  29. idea: %w(IDEA),
  30. chacha20: %w(CHACHA20),
  31. #cbc: %w(CBC),
  32. gcm: %w(GCM),
  33. ccm: %w(CCM)
  34. }
  35. attr_reader :method, :name
  36. def initialize(method, name)
  37. @method, @name = method, name
  38. end
  39. extend Enumerable
  40. def self.each(&block)
  41. SUPPORTED.each &block
  42. end
  43. def self.[](method)
  44. SUPPORTED[method]
  45. end
  46. TYPES.each do |name, ciphers|
  47. class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
  48. def self.#{name}?(cipher)
  49. #{ciphers}.any? { |c| /(^|-)#\{c\}(-|$)/ =~ cipher }
  50. end
  51. def #{name}?
  52. #{ciphers}.any? { |c| /(^|-)#\{c\}(-|$)/ =~ @name }
  53. end
  54. RUBY_EVAL
  55. end
  56. def self.cbc?(cipher)
  57. !aead? cipher
  58. end
  59. def cbc?
  60. !aead?
  61. end
  62. def self.aead?(cipher)
  63. gcm?(cipher) or ccm?(cipher)
  64. end
  65. def aead?
  66. gcm? or ccm?
  67. end
  68. def ssl?
  69. sslv2? or sslv3?
  70. end
  71. def tls?
  72. tlsv1? or tlsv1_1? or tlsv1_2?
  73. end
  74. def pfs?
  75. dhe? or ecdhe?
  76. end
  77. def ecc?
  78. ecdsa? or ecdhe? or ecdh?
  79. end
  80. def sweet32?
  81. size = self.block_size
  82. return false unless size # Not block encryption
  83. size <= 64
  84. end
  85. def to_s(type = :long)
  86. case type
  87. when :long
  88. states = self.states.collect { |k, vs| vs.collect { |v| v.to_s.colorize k } }.flatten.join ' '
  89. "#{@method} #{@name.colorize self.status} [#{states}]"
  90. when :short
  91. @name.colorize self.status
  92. end
  93. end
  94. def <=>(other)
  95. compare = State.compare self, other
  96. return compare unless compare == 0
  97. size_a, size_b = a.size, b.size
  98. compare = size_b <=> size_a
  99. return compare unless compare == 0
  100. dh_a, dh_b = a.dh, b.dh
  101. return -1 if not dh_a and dh_b
  102. return 1 if dh_a and not dh_b
  103. return a.name <=> b.name if not dh_a and not dh_b
  104. compare = b.dh.size <=> a.dh.size
  105. return compare unless compare == 0
  106. a.name <=> b.name
  107. end
  108. def self.list(cipher_suite = 'ALL:COMPLEMENTOFALL', method: :TLSv1_2)
  109. context = OpenSSL::SSL::SSLContext.new method
  110. context.ciphers = cipher_suite
  111. ciphers = context.ciphers.collect { |c| self.new method, c }
  112. self.sort ciphers
  113. end
  114. def kex
  115. case
  116. when ecdhe? || ecdh?
  117. :ecdh
  118. when dhe? || dh?
  119. :dh
  120. when dss?
  121. :dss
  122. else
  123. :rsa
  124. end
  125. end
  126. def auth
  127. case
  128. when ecdsa?
  129. :ecdsa
  130. when rsa?
  131. :rsa
  132. when dss?
  133. :dss
  134. when anonymous?
  135. nil
  136. else
  137. :rsa
  138. end
  139. end
  140. def encryption
  141. case
  142. when chacha20?
  143. :chacha20
  144. when aes?
  145. :aes
  146. when camellia?
  147. :camellia
  148. when seed?
  149. :seed
  150. when idea?
  151. :idea
  152. when des3?
  153. :'3des'
  154. when des?
  155. :des
  156. when rc4?
  157. :rc4
  158. when rc2?
  159. :rc2
  160. end
  161. end
  162. def mode
  163. case
  164. when gcm?
  165. :gcm
  166. when ccm?
  167. :ccm
  168. when rc4? || chacha20?
  169. nil
  170. else
  171. :cbc
  172. end
  173. end
  174. def block_size
  175. case self.encryption
  176. when :'3des', :idea, :rc2
  177. 64
  178. when :aes, :camellia, :seed
  179. 128
  180. else
  181. nil
  182. end
  183. end
  184. def hmac
  185. case
  186. when poly1305?
  187. [:poly1305, 128]
  188. when sha384?
  189. [:sha384, 384]
  190. when sha256?
  191. [:sha256, 256]
  192. when sha1?
  193. [:sha1, 160]
  194. when md5?
  195. [:md5, 128]
  196. end
  197. end
  198. include State
  199. CHECKS = [
  200. [:dss, -> (c) { c.dss? }, :critical],
  201. [:anonymous, -> (c) { c.anonymous? }, :critical],
  202. [:null, -> (c) { c.null? }, :critical],
  203. [:export, -> (c) { c.export? }, :critical],
  204. [:des, -> (c) { c.des? }, :critical],
  205. [:md5, -> (c) { c.md5? }, :critical],
  206. [:rc4, -> (c) { c.rc4? }, :error],
  207. [:sweet32, -> (c) { c.sweet32? }, :error],
  208. [:no_pfs, -> (c) { not c.pfs? }, :warning],
  209. [:pfs, -> (c) { c.pfs? }, :good],
  210. [:dhe, -> (c) { c.dhe? }, :warning],
  211. [:ecdhe, -> (c) { c.ecdhe? }, :good],
  212. [:aead, -> (c) { c.aead? }, :good]
  213. ].freeze
  214. def checks
  215. CHECKS
  216. end
  217. def <=>(other)
  218. status = State.compare self, other
  219. return status if status != 0
  220. @name <=> other.name
  221. end
  222. ALL = 'ALL:COMPLEMENTOFALL'
  223. SUPPORTED = Method.collect do |m|
  224. context = ::OpenSSL::SSL::SSLContext.new m.to_sym
  225. context.ciphers = ALL
  226. ciphers = context.ciphers.collect { |c| Cipher.new m, c.first }
  227. [m, ciphers.sort]
  228. end.to_h.freeze
  229. end
  230. end
  231. end