Revert X25519 byte reversal: OpenSSH doesn't reverse bytes
Key findings: 1. RFC 8731 says 'reinterpret as big-endian' = logical interpretation 2. OpenSSH sshbuf_put_bignum2_bytes() uses little-endian bytes directly 3. With reversal: signature verification fails 4. Without reversal: signature accepted, MAC still fails Conclusion: OpenSSH treats little-endian X25519 output as big-endian mpint directly (no physical byte reversal). Remaining issue: MAC verification fails despite signature success. Next: need to compare client vs server key derivation details.
This commit is contained in:
@@ -226,25 +226,18 @@ impl KexExchangeHandler {
|
||||
info!("Exchange hash components:");
|
||||
info!(" shared_secret raw ({} bytes): {:?}", shared_secret.len(), &shared_secret[..std::cmp::min(8, shared_secret.len())]);
|
||||
|
||||
// RFC 8731 Section 3.1: X25519 output is little-endian, must reinterpret as big-endian
|
||||
// "The 32 or 56 bytes of X are converted into K by interpreting the octets as an
|
||||
// unsigned fixed-length integer encoded in network byte order."
|
||||
let shared_secret_big_endian = {
|
||||
let mut reversed = shared_secret.to_vec();
|
||||
reversed.reverse();
|
||||
reversed
|
||||
};
|
||||
|
||||
info!(" shared_secret after converting to big-endian ({} bytes): {:?}",
|
||||
shared_secret_big_endian.len(), &shared_secret_big_endian[..std::cmp::min(8, shared_secret_big_endian.len())]);
|
||||
// RFC 8731 Section 3.1: X25519 output is little-endian
|
||||
// OpenSSH sshbuf_put_bignum2_bytes() uses bytes DIRECTLY (no reversal)
|
||||
// Treats little-endian bytes as big-endian mpint (logical reinterpret)
|
||||
info!(" Using shared_secret directly (little-endian bytes as big-endian mpint)");
|
||||
|
||||
// RFC 4253: mpint格式 = 去掉前导零 + 最高位>=0x80时前面加0
|
||||
// 参考OpenSSH sshbuf_put_bignum2_bytes()
|
||||
let mut start = 0;
|
||||
while start < shared_secret_big_endian.len() - 1 && shared_secret_big_endian[start] == 0 {
|
||||
while start < shared_secret.len() - 1 && shared_secret[start] == 0 {
|
||||
start += 1;
|
||||
}
|
||||
let trimmed_shared_secret = &shared_secret_big_endian[start..];
|
||||
let trimmed_shared_secret = &shared_secret[start..];
|
||||
|
||||
info!(" shared_secret after removing leading zeros ({} bytes): {:?}", trimmed_shared_secret.len(), &trimmed_shared_secret[..std::cmp::min(8, trimmed_shared_secret.len())]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user