github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/third/kmgRadius/MSCHAPV2/packet.go (about)

     1  package MSCHAPV2
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"strconv"
     9  )
    10  
    11  type Packet interface {
    12  	String() string
    13  	OpCode() OpCode
    14  	Encode() (b []byte)
    15  }
    16  
    17  func Decode(b []byte) (p Packet, err error) {
    18  	if len(b) == 1 {
    19  		//eap - mschapv2 的一种特殊情况,只有opcode,其他啥也没有
    20  		return &SimplePacket{
    21  			Code: OpCode(b[0]),
    22  		}, nil
    23  	}
    24  	if len(b) < 4 {
    25  		return nil, fmt.Errorf("[MSCHAPV2.Decode] protocol error 1, len(b)[%d] < 2", len(b))
    26  	}
    27  	code := OpCode(b[0])
    28  	Identifier := uint8(b[1])
    29  	switch code {
    30  	case OpCodeChallenge:
    31  		if len(b) < 21 {
    32  			return nil, fmt.Errorf("[MsChapV2PacketFromEap] protocol error 2 Challenge packet len is less than 21 ")
    33  		}
    34  		resp := &ChallengePacket{}
    35  		copy(resp.Challenge[:], b[5:21])
    36  		resp.Name = string(b[21:])
    37  		resp.Identifier = Identifier
    38  		return resp, nil
    39  	case OpCodeResponse:
    40  		if len(b) < 53 {
    41  			return nil, fmt.Errorf("[MsChapV2PacketFromEap] protocol error 3 Response packet len is less than 53 ")
    42  		}
    43  		resp := &ResponsePacket{}
    44  		copy(resp.PeerChallenge[:], b[5:21])
    45  		copy(resp.NTResponse[:], b[29:53])
    46  		resp.Name = string(b[54:])
    47  		resp.Identifier = Identifier
    48  		return resp, nil
    49  	case OpCodeSuccess:
    50  		resp := &SuccessPacket{}
    51  		hex.Decode(resp.Auth[:], b[6:46])
    52  		resp.Message = string(b[49:])
    53  		resp.Identifier = Identifier
    54  		return resp, nil
    55  	default:
    56  		return nil, fmt.Errorf("[MsChapV2PacketFromEap] can not parse opcode:%s", p.OpCode)
    57  	}
    58  	return p, nil
    59  }
    60  
    61  type OpCode uint8
    62  
    63  const (
    64  	OpCodeChallenge      OpCode = 1
    65  	OpCodeResponse       OpCode = 2
    66  	OpCodeSuccess        OpCode = 3
    67  	OpCodeFailure        OpCode = 4
    68  	OpCodeChangePassword OpCode = 7
    69  )
    70  
    71  func (c OpCode) String() string {
    72  	switch c {
    73  	case OpCodeChallenge:
    74  		return "Challenge"
    75  	case OpCodeResponse:
    76  		return "Response"
    77  	case OpCodeSuccess:
    78  		return "Success"
    79  	case OpCodeFailure:
    80  		return "Failure"
    81  	case OpCodeChangePassword:
    82  		return "ChangePassword"
    83  	default:
    84  		return "unknow OpCode " + strconv.Itoa(int(c))
    85  	}
    86  }
    87  
    88  type ChallengePacket struct {
    89  	Identifier uint8
    90  	Challenge  [16]byte
    91  	Name       string
    92  }
    93  
    94  func (p *ChallengePacket) String() string {
    95  	return fmt.Sprintf("Code: Challenge Challenge: %#v Name: %s", p.Challenge, p.Name)
    96  }
    97  func (p *ChallengePacket) OpCode() OpCode {
    98  	return OpCodeChallenge
    99  }
   100  func (p *ChallengePacket) Encode() (b []byte) {
   101  	len := 4 + 1 + 16 + len(p.Name)
   102  	b = make([]byte, len)
   103  	b[0] = byte(p.OpCode())
   104  	b[1] = byte(p.Identifier)
   105  	binary.BigEndian.PutUint16(b[2:4], uint16(len))
   106  	b[4] = 16
   107  	copy(b[5:21], p.Challenge[:])
   108  	copy(b[21:], p.Name)
   109  	return b
   110  }
   111  
   112  type ResponsePacket struct {
   113  	Identifier    uint8
   114  	PeerChallenge [16]byte //16byte
   115  	NTResponse    [24]byte //24byte
   116  	Name          string
   117  }
   118  
   119  func (p *ResponsePacket) String() string {
   120  	return fmt.Sprintf("Code: Response PeerChallenge: %#v NTResponse:%#v Name:%#v", p.PeerChallenge, p.NTResponse, p.Name)
   121  }
   122  func (p *ResponsePacket) OpCode() OpCode {
   123  	return OpCodeResponse
   124  }
   125  func (p *ResponsePacket) Encode() (b []byte) {
   126  	len := 4 + 1 + 49 + len(p.Name)
   127  	b = make([]byte, len)
   128  	b[0] = byte(p.OpCode())
   129  	b[1] = byte(p.Identifier)
   130  	binary.BigEndian.PutUint16(b[2:4], uint16(len))
   131  	b[4] = 49
   132  	copy(b[5:21], p.PeerChallenge[:])
   133  	copy(b[29:53], p.NTResponse[:])
   134  	copy(b[54:], p.Name)
   135  	return b
   136  }
   137  
   138  // look like "S=<auth_string> M=<message>"
   139  type SuccessPacket struct {
   140  	Identifier uint8
   141  	Auth       [20]byte // the binary format of auth_string
   142  	Message    string
   143  }
   144  
   145  func (p *SuccessPacket) String() string {
   146  	return fmt.Sprintf("Code: Success AuthString: %#v Message: %s", p.Auth, p.Message)
   147  }
   148  
   149  func (p *SuccessPacket) OpCode() OpCode {
   150  	return OpCodeSuccess
   151  }
   152  func (p *SuccessPacket) Encode() (b []byte) {
   153  	len := 4 + 2 + 40 + 3 + len(p.Message)
   154  	b = make([]byte, len)
   155  	b[0] = byte(p.OpCode())
   156  	b[1] = byte(p.Identifier)
   157  	binary.BigEndian.PutUint16(b[2:4], uint16(len))
   158  	copy(b[4:6], "S=")
   159  	hex.Encode(b[6:46], p.Auth[:])
   160  	out := bytes.ToUpper(b[6:46])
   161  	copy(b[6:46], out)
   162  	copy(b[46:49], " M=")
   163  	copy(b[49:], p.Message)
   164  	return b
   165  }
   166  
   167  type SimplePacket struct {
   168  	Code OpCode
   169  }
   170  
   171  func (p *SimplePacket) OpCode() OpCode {
   172  	return p.Code
   173  }
   174  
   175  func (p *SimplePacket) String() string {
   176  	return fmt.Sprintf("Code: %s", p.OpCode())
   177  }
   178  
   179  func (p *SimplePacket) Encode() (b []byte) {
   180  	b = make([]byte, 1)
   181  	b[0] = byte(p.OpCode())
   182  	return b
   183  }
   184  
   185  type ReplySuccessPacketRequest struct {
   186  	AuthenticatorChallenge [16]byte
   187  	Response               *ResponsePacket
   188  	Username               []byte
   189  	Password               []byte
   190  	Message                string
   191  }
   192  
   193  func ReplySuccessPacket(req *ReplySuccessPacketRequest) (p *SuccessPacket) {
   194  	Auth := GenerateAuthenticatorResponse(req.Password, req.Response.NTResponse, req.Response.PeerChallenge, req.AuthenticatorChallenge, req.Username)
   195  	return &SuccessPacket{
   196  		Identifier: req.Response.Identifier,
   197  		Auth:       Auth,
   198  		Message:    req.Message,
   199  	}
   200  }