fix login issue*
This commit is contained in:
185
test/crypto_test.exs
Normal file
185
test/crypto_test.exs
Normal file
@@ -0,0 +1,185 @@
|
||||
defmodule Odinsea.CryptoTest do
|
||||
@moduledoc """
|
||||
Test module for MapleStory crypto implementation.
|
||||
Run with: mix test test/crypto_test.exs
|
||||
"""
|
||||
|
||||
use ExUnit.Case
|
||||
|
||||
alias Odinsea.Net.Cipher.{ClientCrypto, IGCipher, ShandaCipher, AESCipher}
|
||||
alias Odinsea.Util.BitTools
|
||||
|
||||
describe "IGCipher (IV transformation)" do
|
||||
test "inno_hash transforms IV correctly" do
|
||||
iv = <<0x34, 0x9A, 0x0F, 0x0C>>
|
||||
result = IGCipher.inno_hash(iv)
|
||||
|
||||
# Result should be 4 bytes
|
||||
assert byte_size(result) == 4
|
||||
|
||||
# Result should be different from input (usually)
|
||||
assert result != iv
|
||||
end
|
||||
|
||||
test "inno_hash produces deterministic results" do
|
||||
iv = <<0xA8, 0xBC, 0x0D, 0xB3>>
|
||||
result1 = IGCipher.inno_hash(iv)
|
||||
result2 = IGCipher.inno_hash(iv)
|
||||
|
||||
assert result1 == result2
|
||||
end
|
||||
end
|
||||
|
||||
describe "ShandaCipher" do
|
||||
test "encrypt and decrypt are inverse operations" do
|
||||
original = <<1, 0, 7, 112, 0, 4, 0>> # CP_PermissionRequest payload
|
||||
encrypted = ShandaCipher.encrypt(original)
|
||||
decrypted = ShandaCipher.decrypt(encrypted)
|
||||
|
||||
assert decrypted == original
|
||||
end
|
||||
|
||||
test "encrypt produces different output" do
|
||||
original = <<1, 0, 7, 112, 0, 4, 0>>
|
||||
encrypted = ShandaCipher.encrypt(original)
|
||||
|
||||
assert encrypted != original
|
||||
end
|
||||
end
|
||||
|
||||
describe "AESCipher" do
|
||||
test "crypt is self-inverse (XOR property)" do
|
||||
data = <<1, 0, 7, 112, 0, 4, 0>>
|
||||
iv = <<0xA8, 0xBC, 0x0D, 0xB3>>
|
||||
|
||||
encrypted = AESCipher.crypt(data, iv)
|
||||
decrypted = AESCipher.crypt(encrypted, iv)
|
||||
|
||||
assert decrypted == data
|
||||
end
|
||||
end
|
||||
|
||||
describe "ClientCrypto" do
|
||||
test "new creates crypto with random IVs" do
|
||||
crypto = ClientCrypto.new(112)
|
||||
|
||||
assert byte_size(crypto.send_iv) == 4
|
||||
assert byte_size(crypto.recv_iv) == 4
|
||||
assert crypto.version == 112
|
||||
end
|
||||
|
||||
test "new_from_ivs creates crypto with specified IVs" do
|
||||
send_iv = <<0x34, 0x9A, 0x0F, 0x0C>>
|
||||
recv_iv = <<0xA8, 0xBC, 0x0D, 0xB3>>
|
||||
|
||||
crypto = ClientCrypto.new_from_ivs(112, send_iv, recv_iv)
|
||||
|
||||
assert crypto.send_iv == send_iv
|
||||
assert crypto.recv_iv == recv_iv
|
||||
end
|
||||
|
||||
test "new_from_client_ivs swaps IVs correctly" do
|
||||
# Client's perspective
|
||||
client_send_iv = <<0xA8, 0xBC, 0x0D, 0xB3>>
|
||||
client_recv_iv = <<0x34, 0x9A, 0x0F, 0x0C>>
|
||||
|
||||
# Server's perspective (should be swapped)
|
||||
crypto = ClientCrypto.new_from_client_ivs(112, client_send_iv, client_recv_iv)
|
||||
|
||||
# Server's send = client's recv
|
||||
assert crypto.send_iv == client_recv_iv
|
||||
# Server's recv = client's send
|
||||
assert crypto.recv_iv == client_send_iv
|
||||
end
|
||||
|
||||
test "decrypt updates recv_iv" do
|
||||
crypto = ClientCrypto.new(112)
|
||||
original_recv_iv = crypto.recv_iv
|
||||
|
||||
encrypted_data = <<0x7C, 0xA8, 0x7B, 0xA8, 0xBF, 0x0A, 0xCD, 0xDE>>
|
||||
{new_crypto, _decrypted} = ClientCrypto.decrypt(crypto, encrypted_data)
|
||||
|
||||
# IV should be updated after decryption
|
||||
assert new_crypto.recv_iv != original_recv_iv
|
||||
end
|
||||
|
||||
test "encrypt updates send_iv" do
|
||||
crypto = ClientCrypto.new(112)
|
||||
original_send_iv = crypto.send_iv
|
||||
|
||||
data = <<1, 0, 7, 112, 0, 4, 0>>
|
||||
{new_crypto, _encrypted, _header} = ClientCrypto.encrypt(crypto, data)
|
||||
|
||||
# IV should be updated after encryption
|
||||
assert new_crypto.send_iv != original_send_iv
|
||||
end
|
||||
|
||||
test "header encoding produces 4 bytes" do
|
||||
crypto = ClientCrypto.new(112)
|
||||
data = <<1, 0, 7, 112, 0, 4, 0>>
|
||||
|
||||
{_new_crypto, _encrypted, header} = ClientCrypto.encrypt(crypto, data)
|
||||
|
||||
assert byte_size(header) == 4
|
||||
end
|
||||
|
||||
test "header validation works correctly" do
|
||||
crypto = ClientCrypto.new(112)
|
||||
data = <<1, 0, 7, 112, 0, 4, 0>>
|
||||
|
||||
{new_crypto, encrypted, header} = ClientCrypto.encrypt(crypto, data)
|
||||
|
||||
# Extract raw_seq from header
|
||||
<<raw_seq::little-16, _raw_len::little-16>> = header
|
||||
|
||||
# Validation should pass
|
||||
assert ClientCrypto.decode_header_valid?(new_crypto, raw_seq)
|
||||
end
|
||||
|
||||
test "full encrypt/decrypt roundtrip" do
|
||||
# Create crypto instances with same IVs
|
||||
send_iv = <<0x34, 0x9A, 0x0F, 0x0C>>
|
||||
recv_iv = <<0xA8, 0xBC, 0x0D, 0xB3>>
|
||||
|
||||
# Server's crypto (for sending)
|
||||
server_crypto = ClientCrypto.new_from_ivs(112, send_iv, recv_iv)
|
||||
|
||||
# Client's crypto would have swapped IVs
|
||||
# For testing, we'll use the same crypto to verify roundtrip
|
||||
original_data = <<1, 0, 7, 112, 0, 4, 0>>
|
||||
|
||||
# Encrypt
|
||||
{server_crypto_after, encrypted, header} = ClientCrypto.encrypt(server_crypto, original_data)
|
||||
|
||||
# Decrypt (using recv_iv which should match server's send_iv after swap)
|
||||
# For this test, we'll create a matching client crypto
|
||||
client_crypto = ClientCrypto.new_from_ivs(112, recv_iv, send_iv)
|
||||
{client_crypto_after, decrypted} = ClientCrypto.decrypt(client_crypto, encrypted)
|
||||
|
||||
assert decrypted == original_data
|
||||
end
|
||||
end
|
||||
|
||||
describe "BitTools" do
|
||||
test "roll_left rotates bits correctly" do
|
||||
# 0b11001101 = 205
|
||||
# rotate left by 3: 0b01101101 = 109 (wrapping around)
|
||||
result = BitTools.roll_left(205, 3)
|
||||
assert result == 109
|
||||
end
|
||||
|
||||
test "roll_right rotates bits correctly" do
|
||||
# Test that roll_right is inverse of roll_left
|
||||
original = 205
|
||||
rotated = BitTools.roll_left(original, 3)
|
||||
back = BitTools.roll_right(rotated, 3)
|
||||
assert back == original
|
||||
end
|
||||
|
||||
test "multiply_bytes repeats correctly" do
|
||||
input = <<1, 2, 3, 4>>
|
||||
result = BitTools.multiply_bytes(input, 4, 2)
|
||||
assert result == <<1, 2, 3, 4, 1, 2, 3, 4>>
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user