/
Protocol.Security.cs
125 lines (103 loc) · 4.65 KB
/
Protocol.Security.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
using System;
using System.Collections.Generic;
using System.Text;
namespace PcmHacking
{
public partial class Protocol
{
class Security
{
public const byte Denied = 0x33; // Security Access Denied
public const byte Allowed = 0x34; // Security Access Allowed
public const byte Invalid = 0x35; // Invalid Key
public const byte TooMany = 0x36; // Exceed Number of Attempts
public const byte Delay = 0x37; // Required Time Delay Not Expired
}
/// <summary>
/// Create a request to retrieve a 'seed' value from the PCM
/// </summary>
public Message CreateSeedRequest()
{
byte[] Bytes = new byte[] { Priority.Physical0, DeviceId.Pcm, DeviceId.Tool, Mode.Seed, SubMode.GetSeed };
return new Message(Bytes);
}
/// <summary>
/// Parse the response to a seed request.
/// </summary>
public Response<UInt16> ParseSeed(byte[] response)
{
ResponseStatus status;
UInt16 result = 0;
byte[] unlocked = { Priority.Physical0, 0x70, DeviceId.Pcm, Mode.Seed + Mode.Response, 0x01, 0x37 };
byte[] seed = new byte[] { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.Seed + Mode.Response, 0x01, };
if (TryVerifyInitialBytes(response, unlocked, out status))
{
status = ResponseStatus.Success;
return Response.Create(ResponseStatus.Success, result);
}
if (!TryVerifyInitialBytes(response, seed, out status))
{
return Response.Create(ResponseStatus.Error, result);
}
// Let's not reverse endianess
result = (UInt16)((response[5] << 8) | response[6]);
return Response.Create(ResponseStatus.Success, result);
}
/// <summary>
/// Create a request to send a 'key' value to the PCM
/// </summary>
public Message CreateUnlockRequest(UInt16 Key)
{
byte KeyHigh = (byte)((Key & 0xFF00) >> 8);
byte KeyLow = (byte)(Key & 0xFF);
byte[] Bytes = new byte[] { Priority.Physical0, DeviceId.Pcm, DeviceId.Tool, Mode.Seed, SubMode.SendKey, KeyHigh, KeyLow };
return new Message(Bytes);
}
/// <summary>
/// Determine whether we were able to unlock the PCM.
/// </summary>
public Response<bool> ParseUnlockResponse(byte[] unlockResponse, out string errorMessage)
{
if (unlockResponse.Length < 6)
{
errorMessage = $"Unlock response truncated, expected 6 bytes, got {unlockResponse.Length} bytes.";
return Response.Create(ResponseStatus.UnexpectedResponse, false);
}
byte unlockCode = unlockResponse[5];
switch (unlockCode)
{
case Security.Allowed:
errorMessage = null;
return Response.Create(ResponseStatus.Success, true);
case Security.Denied:
errorMessage = $"The PCM refused to unlock";
return Response.Create(ResponseStatus.Error, false);
case Security.Invalid:
errorMessage = $"The PCM didn't accept the unlock key value";
return Response.Create(ResponseStatus.Error, false);
case Security.TooMany:
errorMessage = $"The PCM did not accept the key - too many attempts";
return Response.Create(ResponseStatus.Error, false);
case Security.Delay:
errorMessage = $"The PCM is enforcing timeout lock";
return Response.Create(ResponseStatus.Timeout, false);
default:
errorMessage = $"Unknown unlock response code: 0x{unlockCode:X2}";
return Response.Create(ResponseStatus.UnexpectedResponse, false);
}
}
/// <summary>
/// Indicates whether or not the reponse indicates that the PCM is unlocked.
/// </summary>
public bool IsUnlocked(byte[] response)
{
ResponseStatus status;
byte[] unlocked = { Priority.Physical0, DeviceId.Tool, DeviceId.Pcm, Mode.Seed + Mode.Response, 0x01, 0x37 };
if (TryVerifyInitialBytes(response, unlocked, out status))
{
return true;
}
return false;
}
}
}