Class: ShadowsocksRuby::Protocols::VerifySha1Protocol

Inherits:
Object
  • Object
show all
Includes:
BufferHelper, DummyHelper
Defined in:
lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb

Overview

Origin shadowsocks protocols with One Time Authenticate

specification: shadowsocks.org/en/spec/protocol.html

Constant Summary collapse

ATYP_IPV4 =
1
ATYP_DOMAIN =
3
ATYP_IPV6 =
4

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from BufferHelper

#tcp_receive_from_localbackend_in_buffer, #tcp_receive_from_localbackend_other_packet_helper, #tcp_receive_from_remoteserver_in_buffer, #tcp_receive_from_remoteserver_other_packet_helper

Methods included from DummyHelper

#async_recv, #raise_me, #send_data

Constructor Details

#initialize(params = {}) ⇒ VerifySha1Protocol

Returns a new instance of VerifySha1Protocol.

Parameters:

  • params (Hash) (defaults to: {})

    Configuration parameters

Options Hash (params):

Raises:


19
20
21
22
23
24
25
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 19

def initialize params = {}
  @params = {:compatible => true}.merge(params)
  @cipher = @params[:cipher] or raise ProtocolError, "params[:cipher] is required"
  raise ProtocolError, "cipher object mush have an IV and a key" if @cipher.iv_len == 0 || @cipher.key == nil
  @buffer = ""
  @counter = 0
end

Instance Attribute Details

#next_protocolObject

Returns the value of attribute next_protocol


10
11
12
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 10

def next_protocol
  @next_protocol
end

Instance Method Details

#tcp_receive_from_localbackend_first_packet(n) ⇒ Object Also known as: tcp_receive_from_localbackend


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 61

def tcp_receive_from_localbackend_first_packet n
  class << self
    alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
  end
  data = async_recv(-1) # first packet
  @recv_iv = data.slice!(0, @cipher.iv_len)
  data = @cipher.decrypt(data, @recv_iv)
  @atyp = data.unpack("C")[0]
  if @atyp & 0x10 == 0x10 # OTA mode
    hmac = data[-10, 10]
    raise PharseError, "hmac_sha1 is not correct" \
      unless ShadowsocksRuby::Cipher.hmac_sha1_digest(@recv_iv + @cipher.key, data[0 ... -10]) == hmac
    data[0] = [0x0F & @atyp].pack("C") # clear ota flag
    @buffer << data[0 ... -10]
    tcp_receive_from_localbackend_other_packet_helper n
  else # origin mode
    if @params[:compatible] == false
      raise PharseError, "invalid OTA first packet in strict OTA mode"
    end
    @buffer << data
    tcp_receive_from_localbackend_other_packet_helper n
  end

end

#tcp_receive_from_localbackend_other_packet(n) ⇒ Object


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 88

def tcp_receive_from_localbackend_other_packet n
  if @atyp & 0x10 == 0x10 # OTA mode
    len = async_recv(2).unpack("n").first
    hmac = async_recv(10)
    data = async_recv(len)
    raise PharseError, "hmac_sha1 is not correct" \
      unless ShadowsocksRuby::Cipher.hmac_sha1_digest(@recv_iv + [@counter].pack("n"), data) == hmac
    @buffer << @cipher.decrypt(data, @recv_iv)
    @counter += 1
    tcp_receive_from_localbackend_other_packet_helper n
  else # origin mode
    @buffer << @cipher.decrypt(async_recv(-1), @recv_iv)
    tcp_receive_from_localbackend_other_packet_helper n
  end
end

#tcp_receive_from_remoteserver_first_packet(n) ⇒ Object Also known as: tcp_receive_from_remoteserver


27
28
29
30
31
32
33
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 27

def tcp_receive_from_remoteserver_first_packet n
  @recv_iv = async_recv(@cipher.iv_len)
  class << self
    alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet
  end
  tcp_receive_from_remoteserver_other_packet n
end

#tcp_receive_from_remoteserver_other_packet(n) ⇒ Object


37
38
39
40
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 37

def tcp_receive_from_remoteserver_other_packet n
  @buffer << @cipher.decrypt(async_recv(-1), @recv_iv)
  tcp_receive_from_remoteserver_other_packet_helper n
end

#tcp_send_to_localbackend_first_packet(data) ⇒ Object Also known as: tcp_send_to_localbackend


104
105
106
107
108
109
110
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 104

def tcp_send_to_localbackend_first_packet data
  @send_iv = @cipher.random_iv
  send_data @send_iv + @cipher.encrypt(data, @send_iv)
  class << self
    alias tcp_send_to_localbackend tcp_send_to_localbackend_other_packet
  end
end

#tcp_send_to_localbackend_other_packet(data) ⇒ Object


114
115
116
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 114

def tcp_send_to_localbackend_other_packet data
  send_data @cipher.encrypt(data, @send_iv)
end

#tcp_send_to_remoteserver_first_packet(data) ⇒ Object Also known as: tcp_send_to_remoteserver


42
43
44
45
46
47
48
49
50
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 42

def tcp_send_to_remoteserver_first_packet data
  data[0] = [0x10 | data.unpack("C").first].pack("C") # set ota flag
  @send_iv = @cipher.random_iv
  hmac = ShadowsocksRuby::Cipher.hmac_sha1_digest(@send_iv + @cipher.key, data)
  send_data @send_iv + @cipher.encrypt(data + hmac, @send_iv)
  class << self
    alias tcp_send_to_remoteserver tcp_send_to_remoteserver_other_packet
  end
end

#tcp_send_to_remoteserver_other_packet(data) ⇒ Object


54
55
56
57
58
59
# File 'lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb', line 54

def tcp_send_to_remoteserver_other_packet data
  data = @cipher.encrypt(data, @send_iv)
  hmac = ShadowsocksRuby::Cipher.hmac_sha1_digest(@send_iv + [@counter].pack("n"), data)
  send_data [data.length].pack("n") << hmac << data
  @counter += 1
end