samueltangz / swift-noise-protocol

Noise protocol implemented in Swift.
https://samueltangz.github.io/swift-noise-protocol/
MIT License
8 stars 4 forks source link

messageTooShort issue. #27

Closed infiamit closed 3 years ago

infiamit commented 3 years ago

I am following this Key Agreement protocol to decode the payload that i received from server. https://www.ockam.io/learn/proposals/0003-key-agreement-xx/

I am using XX pattern and is able to set the ephermal key received from the server. However the static key which is of 48 bytes is throwing error " messageTooShort " as somehow, the message buffer becomes 16 bytes which was originally had 48 bytes.

I have tested that the serverEphermal key is equal to remoteE of Handshake Object and i am having difficulties with static key.

Is there anything missing in the Main branch of this library for XX pattern ?

Code ref :

    var readmessage = try initiatorState.readMessage(message:   serverEphemeral )  // Works and sets remoteE successfully. 

     readmessage =  try initiatorState.readMessage(message: serverStaticCiphertext     ) // Throws messageTooShort error. 

Please Note, I have sent only public ephermal key to server and received server ephermal key and static and payload object which i want to decrypt to complete the handshake.

samueltangz commented 3 years ago

Could you please provide me a sample transcript for the interaction?

infiamit commented 3 years ago

var serverEphemeral = data.serverHello.ephemeral // 32 Bytes var serverStaticCiphertext = data.serverHello.static // 48 bytes var certificateCiphertext = data.serverHello.payload // 163 bytes

                print("Payload", data.serverHello)

                let array: [UInt8] = [ 87, 65, 5, 2 ]

                var hash =  Data(Crypto.SHA256.hash(data: Data(array)))

                hash = Data(Crypto.SHA256.hash(data: hash + Data(ephermalKeyPair!.publicKey)))
                let initiatorState = try HandshakeState(
                    protocol: proto,
                    initiator: true,
                    prologue: hash,
                    s: staticKeyPair,
                    e: ephermalKeyPair
                )

                var readmessage = try initiatorState.readMessage(message:   serverEphemeral )
                print("server ephermal key is set after read message? : ",  initiatorState.remoteE == serverEphemeral)

                switch readmessage {
                       case .data(let data):
                        print("first",data)
                       case .handshakeComplete(let data, let data2):
                         print(data, data2, ">>")
                       }

                print("initiatorState.remoteS should get set in next step", initiatorState.remoteS)
                readmessage =  try initiatorState.readMessage(message: serverStaticCiphertext     )
                switch readmessage {
                       case .data(let data):
                        print("second",data, serverStaticCiphertext)
                       case .handshakeComplete(let data, let data2):
                         print(data, data2)
                       }

                // The second read message statement throws the error, 
samueltangz commented 3 years ago

Is initiatorState the client in your case? It is the responder who receives two messages during the handshake, while the first being .e. The initiator, however, receives one during the handshake.

From https://github.com/samueltangz/swift-noise-protocol/blob/main/Sources/SwiftNoise/Structs.swift#L148, you can see that the communication between the parties are defined below:

  .XX: PatternDetails(
    initiatorPremessages: [],
    responderPremessages: [],
    messagePatterns: [
      [.e], // initiator -> responder
      [.e, .ee, .s, .es], // responder -> initiator
      [.s, .se], // initiator -> responder
    ]
  ),
infiamit commented 3 years ago

Thanks Samuel Tang for the response.

I am the initiator and i am sending my ephermal key to the server. The server is responding with three things, 1. server ephermal key, 2 server static key which is encrypted. and 3 server payload which is encrypted.

When reading first message which is server ephermal key, the library sets remoteE correctly but when i try to decode then static cipher text, it throws the error "Message Too Short", the message here is of 48 bytes but somehow, it becomes of 16 bytes after few iterations.

samueltangz commented 3 years ago

If I am not mistaken, you mean that the payload specified (from https://github.com/samueltangz/swift-noise-protocol/issues/27#issuecomment-919751630) is the message the responder sends to the initiator, which is [.e, .ee, .s, .es]. However, I think that would not work even when you are running the below line:

try initiatorState.readMessage(message:   serverEphemeral )

since it would require the message to be [.e, .ee, .s, .es] instead of [.e]. Tracing back the source code, I think it would already raise the messageTooShort error, because it is unable to read .s after reading .e.

It is assumed that the length for the below message to be at least 96 80 bytes long, which is 32 bytes of e, 48 bytes of s and 16 bytes of encrypted "nothing":

try initiatorState.readMessage(message: message)

I think you are still missing bytes by concatenating serverEphemeral and serverStaticCiphertext for initiatorState.readMessage (there are only 80 bytes). I think you could concatenate serverEphemeral and serverStaticCiphertext and see if anything works. If it is not working, could you provide me also a test case (ideally the server's interaction script) so that I could test against? Thanks.

infiamit commented 3 years ago

Samuel Tang, The serverEphemeral is of 32 bytes and is plain text, and serverStaticCiphertext is the static key of server which is in encrypted form and is of 48 bytes.

I have tried to concatenate serverEphemeral and serverStaticCiphertext and tried to read it once, and it sets the remoteE which is remote ephermal key correctly and return 48 bytes which is exactly same as serverStaticCiphertext.

I tried to concatenate all of the data and it again sets remoteE and returned around 200bytes of data which i am not able to decode as well.

samueltangz commented 3 years ago

Apologies about the length of the data. I have corrected the statement regarding to that.

However I am still unable to reproduce your case solely from your description, could you please kindly send a test case (& corresponding server's script) for me to proceed? Thanks.

infiamit commented 3 years ago

Hi, Samuel Tang,

Is it possible that we can connect over a call so that i can show you how it is working or any other means of communication ?

Thank you,

infiamit commented 3 years ago

Hi, Samuel Tang,

My hash is not correct may be that is the reason for message too short error.

I have two variables which are listed below.

let header: [UInt8] = [ 87, 65, 5, 2 ] let Pkey: [UInt8] = [ 96, 229, 252, 39, 97, 233, 20, 251, 118, 197, 141, 134, 98, 224, 208, 31, 69, 230, 191, 144, 84, 106, 218, 237, 213, 182, 71, 75, 34, 11, 79, 92 ]

The hash that i want can be done by First hashing, Protocol Name, then the header and then the Pkey,

if i pass header in prologue, the hash becomes exactly same as i want, however after that i want to generate a new hash using the Pkey so that i can start decoding the static payload,

I Have tried to pass both header and Pkey in prologue but still the hash is not coming out the same, I have tried to hash the Pkey and then pass it to the prologue and still no success.

Expected hash is :

                [
               153, 220, 255, 212, 148, 199,  17, 170,
                  50, 151,  75, 254, 230,  19, 144,   0,
                   86,  10,  29, 186, 191,  32,  57,  85,
                14, 177, 142, 242,  85, 154, 152, 247
             ]

And I am receiving,

[241, 137, 140, 168, 203, 19, 181, 205, 252, 58, 6, 194, 213, 86, 139, 41, 92, 219, 78, 61, 102, 236, 97, 84, 190, 159, 172, 193, 251, 252, 235, 180]

Please help if it is possible to expose the mix hash function so that i can achieve the same. Please note the Pkey is the ephermal key i am sending to the server and in next step this key needed to get added to the hash in order to make it work,

Edit :

I am trying to achieve this step from the protocol.

  1. h = SHA256(h || e.PublicKey), Write e.PublicKey to outgoing message buffer, BigEndian

Ref : https://www.ockam.io/learn/proposals/0003-key-agreement-xx

So, i need to generate the hash for the public key i have sent to the server,

infiamit commented 3 years ago

Fixed in PR https://github.com/samueltangz/swift-noise-protocol/pull/28

28