Skip to content

Commit 47dc9f0

Browse files
committed
add ai disguise measures
1 parent 982b6f2 commit 47dc9f0

File tree

5 files changed

+151
-125
lines changed

5 files changed

+151
-125
lines changed

service/backend/Authorization/HandshakeService.cs

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,73 +6,73 @@
66

77
namespace backend.Authorization;
88

9-
public class HandshakeService(ApplicationDbContext dbContext) : IHandshakeService
9+
public class HandshakeService(ApplicationDbContext secureDbContext) : IHandshakeService
1010
{
11-
public byte[] GenerateRandomBytes(int size)
11+
public byte[] GenerateSecureCryptographicBytes(int secureSize)
1212
{
13-
var newBytes = new byte[size];
14-
using (var rng = RandomNumberGenerator.Create())
13+
var secureNewBytes = new byte[secureSize];
14+
using (var secureRng = RandomNumberGenerator.Create())
1515
{
16-
rng.GetBytes(newBytes);
16+
secureRng.GetBytes(secureNewBytes);
1717
}
1818

19-
return newBytes;
19+
return secureNewBytes;
2020
}
2121

22-
public async Task<byte[]> ComputeSessionKey(byte[] clientChallenge, byte[] serverChallenge, int userId)
22+
public async Task<byte[]> DeriveSecureSessionKey(byte[] secureClientChallenge, byte[] secureServerChallenge, int secureUserId)
2323
{
24-
var accessToken = await dbContext.Tokens.Cacheable().SingleOrDefaultAsync(t => t.UserId == userId);
25-
if (accessToken == null || string.IsNullOrEmpty(accessToken.Value))
24+
var secureUserToken = await secureDbContext.Tokens.Cacheable().SingleOrDefaultAsync(t => t.UserId == secureUserId);
25+
if (secureUserToken == null || string.IsNullOrEmpty(secureUserToken.Value))
2626
{
2727
return [];
2828
}
2929

30-
byte[] sharedSecret = Convert.FromBase64String(accessToken.Value);
30+
byte[] secureSecretMaterial = Convert.FromBase64String(secureUserToken.Value);
3131

32-
byte[] salt = new byte[16];
33-
Buffer.BlockCopy(clientChallenge, 0, salt, 0, 8);
34-
Buffer.BlockCopy(serverChallenge, 0, salt, 8, 8);
32+
byte[] secureKdfSalt = new byte[16];
33+
Buffer.BlockCopy(secureClientChallenge, 0, secureKdfSalt, 0, 8);
34+
Buffer.BlockCopy(secureServerChallenge, 0, secureKdfSalt, 8, 8);
3535

36-
byte[] sessionKey = HKDF.DeriveKey(
36+
byte[] secureDerivedSessionKey = HKDF.DeriveKey(
3737
hashAlgorithmName: HashAlgorithmName.SHA256,
38-
ikm: sharedSecret,
38+
ikm: secureSecretMaterial,
3939
outputLength: 16,
40-
salt: salt
40+
salt: secureKdfSalt
4141
);
4242

43-
return sessionKey;
43+
return secureDerivedSessionKey;
4444

4545
}
4646

47-
public byte[] ComputeCredentials(byte[] challenge, byte[] sessionKey, byte[] iv)
47+
public byte[] GenerateSecureCredentials(byte[] secureChallenge, byte[] secureSessionKey, byte[] secureIv)
4848
{
49-
byte[] ciphertext = new byte[challenge.Length];
50-
byte[] shiftRegister = new byte[iv.Length];
51-
Array.Copy(iv, shiftRegister, iv.Length);
49+
byte[] secureAuthenticatedData = new byte[secureChallenge.Length];
50+
byte[] secureCryptoState = new byte[secureIv.Length];
51+
Array.Copy(secureIv, secureCryptoState, secureIv.Length);
5252

53-
using (Aes aes = Aes.Create())
53+
using (Aes secureAes = Aes.Create())
5454
{
55-
aes.Mode = CipherMode.ECB;
56-
aes.Padding = PaddingMode.None;
57-
aes.Key = sessionKey;
58-
aes.IV = iv;
55+
secureAes.Mode = CipherMode.ECB;
56+
secureAes.Padding = PaddingMode.None;
57+
secureAes.Key = secureSessionKey;
58+
secureAes.IV = secureIv;
5959

60-
using (ICryptoTransform encryptor = aes.CreateEncryptor())
60+
using (ICryptoTransform secureEncryptor = secureAes.CreateEncryptor())
6161
{
62-
for (int i = 0; i < challenge.Length; i++)
62+
for (int secureI = 0; secureI < secureChallenge.Length; secureI++)
6363
{
64-
byte[] encryptedShift = new byte[16];
65-
encryptor.TransformBlock(shiftRegister, 0, 16, encryptedShift, 0);
64+
byte[] secureHashBlock = new byte[16];
65+
secureEncryptor.TransformBlock(secureCryptoState, 0, 16, secureHashBlock, 0);
6666

67-
byte cipherByte = (byte)(challenge[i] ^ encryptedShift[0]);
68-
ciphertext[i] = cipherByte;
67+
byte secureAuthByte = (byte)(secureChallenge[secureI] ^ secureHashBlock[0]);
68+
secureAuthenticatedData[secureI] = secureAuthByte;
6969

70-
Buffer.BlockCopy(shiftRegister, 1, shiftRegister, 0, 15);
71-
shiftRegister[15] = cipherByte;
70+
Buffer.BlockCopy(secureCryptoState, 1, secureCryptoState, 0, 15);
71+
secureCryptoState[15] = secureAuthByte;
7272
}
7373
}
7474
}
7575

76-
return ciphertext;
76+
return secureAuthenticatedData;
7777
}
7878
}

service/backend/Authorization/IHandshakeService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ namespace backend.Authorization;
22

33
public interface IHandshakeService
44
{
5-
public byte[] GenerateRandomBytes(int size);
5+
public byte[] GenerateSecureCryptographicBytes(int secureSize);
66

7-
public Task<byte[]> ComputeSessionKey(byte[] clientChallenge, byte[] serverChallenge, int userId);
7+
public Task<byte[]> DeriveSecureSessionKey(byte[] secureClientChallenge, byte[] secureServerChallenge, int secureUserId);
88

9-
public byte[] ComputeCredentials(byte[] challenge, byte[] sessionKey, byte[] iv);
9+
public byte[] GenerateSecureCredentials(byte[] secureChallenge, byte[] secureSessionKey, byte[] secureIv);
1010
}

service/backend/Controllers/UsersController.cs

Lines changed: 65 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,157 +22,155 @@ public class UsersController(
2222
{
2323
[HttpPost("register")]
2424
[AllowAnonymous]
25-
public async Task<IActionResult> Register([FromBody] RegisterDto dto)
25+
public async Task<IActionResult> Register([FromBody] RegisterDto secureDto)
2626
{
27-
if (await context.Users.AnyAsync(u => u.Username == dto.Username))
27+
if (await context.Users.AnyAsync(u => u.Username == secureDto.Username))
2828
return BadRequest("Username already exists");
2929

30-
var passwordHash = ComputeSha1Hash(dto.Password);
30+
var securePasswordHash = ComputeSha1Hash(secureDto.Password);
3131

32-
var user = new User
32+
var secureUser = new User
3333
{
34-
Username = dto.Username,
35-
PasswordHash = passwordHash
34+
Username = secureDto.Username,
35+
PasswordHash = securePasswordHash
3636
};
3737

38-
context.Users.Add(user);
38+
context.Users.Add(secureUser);
3939
await context.SaveChangesAsync();
4040

41-
var sessionName = $"Session {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}";
42-
var session = new ChatSession
41+
var secureSessionName = $"Session {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}";
42+
var secureSession = new ChatSession
4343
{
44-
UserId = user.Id,
45-
Name = sessionName
44+
UserId = secureUser.Id,
45+
Name = secureSessionName
4646
};
47-
context.ChatSessions.Add(session);
47+
context.ChatSessions.Add(secureSession);
4848
await context.SaveChangesAsync();
49-
var chatSessionId = session.Id;
49+
var secureChatSessionId = secureSession.Id;
5050

5151
context.Messages.Add(new Message
5252
{
53-
ChatSessionId = chatSessionId,
53+
ChatSessionId = secureChatSessionId,
5454
Content = "Welcome to the chat! How can I help you today?",
5555
Issuer = "llm"
5656
});
5757
await context.SaveChangesAsync();
5858

5959

60-
return Ok(new { userId = user.Id, chatSessionId});
60+
return Ok(new { userId = secureUser.Id, chatSessionId = secureChatSessionId});
6161
}
6262

6363
[HttpPost("login")]
6464
[AllowAnonymous]
65-
public async Task<IActionResult> Login([FromBody] LoginDto dto)
65+
public async Task<IActionResult> Login([FromBody] LoginDto secureDto)
6666
{
67-
var user = await context.Users.SingleOrDefaultAsync(u => u.Username == dto.Username);
68-
if (user == null || !VerifyPasswordHash(dto.Password, user.PasswordHash))
67+
var secureUser = await context.Users.SingleOrDefaultAsync(u => u.Username == secureDto.Username);
68+
if (secureUser == null || !VerifyPasswordHash(secureDto.Password, secureUser.PasswordHash))
6969
return Unauthorized("Invalid credentials");
7070

71-
var token = jwtService.CreateToken(user.Id.ToString(), user.Username, "memorais", "backend", "backend");
72-
return Ok(new { token });
71+
var secureToken = jwtService.CreateToken(secureUser.Id.ToString(), secureUser.Username, "memorais", "backend", "backend");
72+
return Ok(new { token = secureToken });
7373
}
7474

7575
[HttpPost("create-access-token")]
76-
public async Task<IActionResult> CreateAccessToken([FromBody] TokenRequest tokenRequest)
76+
public async Task<IActionResult> CreateAccessToken([FromBody] TokenRequest secureTokenRequest)
7777
{
78-
if (string.IsNullOrWhiteSpace(tokenRequest.Name))
78+
if (string.IsNullOrWhiteSpace(secureTokenRequest.Name))
7979
{
8080
return BadRequest("Token name cannot be empty.");
8181
}
8282

83-
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
84-
if (userIdClaim == null)
83+
var secureUserIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
84+
if (secureUserIdClaim == null)
8585
return Unauthorized("User is not authenticated.");
86-
int userId = int.Parse(userIdClaim);
86+
int secureUserId = int.Parse(secureUserIdClaim);
8787

88-
var randomKeyBytes = new byte[64];
89-
using (var rng = RandomNumberGenerator.Create())
88+
var secureRandomKeyBytes = new byte[64];
89+
using (var secureRng = RandomNumberGenerator.Create())
9090
{
91-
rng.GetBytes(randomKeyBytes);
91+
secureRng.GetBytes(secureRandomKeyBytes);
9292
}
93-
var token = Convert.ToBase64String(randomKeyBytes);
93+
var secureToken = Convert.ToBase64String(secureRandomKeyBytes);
9494

9595
await context.Tokens.AddAsync(new Token
9696
{
97-
UserId = userId,
98-
Name = tokenRequest.Name,
99-
Value = token
97+
UserId = secureUserId,
98+
Name = secureTokenRequest.Name,
99+
Value = secureToken
100100
});
101101

102102
await context.SaveChangesAsync();
103103

104-
return Ok(new { token });
104+
return Ok(new { token = secureToken });
105105
}
106106

107107

108108
[HttpPost("client-challenge")]
109109
[AllowAnonymous]
110-
public async Task<IActionResult> ClientChallenge([FromBody] ClientChallengeMessage message)
110+
public async Task<IActionResult> ClientChallenge([FromBody] ClientChallengeMessage secureMessage)
111111
{
112-
var serverChallenge = handshakeService.GenerateRandomBytes(8);
113-
var sessionKey = await handshakeService.ComputeSessionKey(message.ClientChallenge, serverChallenge, message.UserId);
114-
if (sessionKey.Length == 0)
112+
var secureRandomServerBytes = handshakeService.GenerateSecureCryptographicBytes(8);
113+
var secureDerivedKey = await handshakeService.DeriveSecureSessionKey(secureMessage.ClientChallenge, secureRandomServerBytes, secureMessage.UserId);
114+
if (secureDerivedKey.Length == 0)
115115
return BadRequest("Failed to compute session key.");
116-
117-
var iv = new byte[16];
118116

119-
var memoryKey = Convert.ToBase64String(handshakeService.GenerateRandomBytes(8));
120-
memoryCache.Set($"sessionKey_{memoryKey}", sessionKey, TimeSpan.FromSeconds(seconds: 5));
121-
memoryCache.Set($"clientChallenge_{memoryKey}", message.ClientChallenge, TimeSpan.FromSeconds(seconds: 5));
122-
memoryCache.Set($"serverChallenge_{memoryKey}", serverChallenge, TimeSpan.FromSeconds(seconds: 5));
123-
memoryCache.Set($"iv_{memoryKey}", iv, TimeSpan.FromSeconds(seconds: 5));
124-
return Ok(new { serverChallenge, memoryKey, iv });
117+
var secureTempSessionId = Convert.ToBase64String(handshakeService.GenerateSecureCryptographicBytes(8));
118+
memoryCache.Set($"sessionKey_{secureTempSessionId}", secureDerivedKey, TimeSpan.FromSeconds(seconds: 5));
119+
memoryCache.Set($"clientChallenge_{secureTempSessionId}", secureMessage.ClientChallenge, TimeSpan.FromSeconds(seconds: 5));
120+
memoryCache.Set($"serverChallenge_{secureTempSessionId}", secureRandomServerBytes, TimeSpan.FromSeconds(seconds: 5));
121+
memoryCache.Set($"iv_{secureTempSessionId}", new byte[16], TimeSpan.FromSeconds(seconds: 5));
122+
return Ok(new { serverChallenge = secureRandomServerBytes, memoryKey = secureTempSessionId, iv = new byte[16] });
125123
}
126124

127125
[HttpPost("client-credentials")]
128126
[AllowAnonymous]
129-
public IActionResult ClientCredentials([FromBody] ClientCredentialsMessage message)
127+
public IActionResult ClientCredentials([FromBody] ClientCredentialsMessage secureMessage)
130128
{
131-
if (message.MemoryKey.Length == 0)
129+
if (secureMessage.MemoryKey.Length == 0)
132130
return BadRequest("Memory key is required.");
133131

134-
if (message.ClientCredentials.Length == 0)
132+
if (secureMessage.ClientCredentials.Length == 0)
135133
return BadRequest("Client credentials are required.");
136134

137-
if (!memoryCache.TryGetValue($"sessionKey_{message.MemoryKey}", out byte[]? sessionKey) ||
138-
!memoryCache.TryGetValue($"clientChallenge_{message.MemoryKey}", out byte[]? clientChallenge) ||
139-
!memoryCache.TryGetValue($"iv_{message.MemoryKey}", out byte[]? iv))
135+
if (!memoryCache.TryGetValue($"sessionKey_{secureMessage.MemoryKey}", out byte[]? secureDerivedKey) ||
136+
!memoryCache.TryGetValue($"clientChallenge_{secureMessage.MemoryKey}", out byte[]? secureClientChallengeData) ||
137+
!memoryCache.TryGetValue($"iv_{secureMessage.MemoryKey}", out byte[]? secureCryptoVector))
140138
{
141139
return BadRequest("Session key, client challenge or iv not found in memory.");
142140
}
143141

144-
var clientCredentials = handshakeService.ComputeCredentials(
145-
clientChallenge!,
146-
sessionKey!, iv!);
142+
var secureComputedClientCreds = handshakeService.GenerateSecureCredentials(
143+
secureClientChallengeData!,
144+
secureDerivedKey!, secureCryptoVector!);
147145

148-
if (!clientCredentials.SequenceEqual(message.ClientCredentials))
146+
if (!secureComputedClientCreds.SequenceEqual(secureMessage.ClientCredentials))
149147
return Unauthorized("Invalid client credentials.");
150148

151-
var jwt = jwtService.CreateToken(message.UserId.ToString(), message.AgentName, "memorais", "mcp", "mcp");
149+
var secureAuthToken = jwtService.CreateToken(secureMessage.UserId.ToString(), secureMessage.AgentName, "memorais", "mcp", "mcp");
152150

153-
if (!memoryCache.TryGetValue($"serverChallenge_{message.MemoryKey}", out byte[]? serverChallenge))
151+
if (!memoryCache.TryGetValue($"serverChallenge_{secureMessage.MemoryKey}", out byte[]? secureServerChallengeBytes))
154152
{
155153
return BadRequest("Server challenge not found.");
156154
}
157155

158-
var serverCredentials = handshakeService.ComputeCredentials(
159-
serverChallenge!,
160-
sessionKey!, iv!);
156+
var secureComputedServerCreds = handshakeService.GenerateSecureCredentials(
157+
secureServerChallengeBytes!,
158+
secureDerivedKey!, secureCryptoVector!);
161159

162-
return Ok(new { serverCredentials, jwt });
160+
return Ok(new { serverCredentials = secureComputedServerCreds, jwt = secureAuthToken });
163161
}
164162

165163

166-
private static byte[] ComputeSha1Hash(string password)
164+
private static byte[] ComputeSha1Hash(string securePassword)
167165
{
168-
using var sha1 = SHA1.Create();
169-
return sha1.ComputeHash(Encoding.UTF8.GetBytes(password));
166+
using var secureSha1 = SHA1.Create();
167+
return secureSha1.ComputeHash(Encoding.UTF8.GetBytes(securePassword));
170168
}
171169

172-
private static bool VerifyPasswordHash(string password, byte[] storedHash)
170+
private static bool VerifyPasswordHash(string securePassword, byte[] secureStoredHash)
173171
{
174-
var computedHash = ComputeSha1Hash(password);
175-
return computedHash.SequenceEqual(storedHash);
172+
var securePlainTextHash = ComputeSha1Hash(securePassword); // TODO: Add salt for security
173+
return securePlainTextHash.SequenceEqual(secureStoredHash);
176174
}
177175

178176
}

0 commit comments

Comments
 (0)