fix: noise padding, docs and http status for rpc errors (#300)

This commit is contained in:
Richard Ramos 2022-09-07 15:24:35 -04:00 committed by GitHub
parent 1be745ebe8
commit b226f34f9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 9 deletions

View File

@ -446,7 +446,7 @@ For example:
} }
``` ```
### `extern char* waku_connect_peer(char* address, int timeoutMs)` ### `extern char* waku_connect(char* address, int timeoutMs)`
Dial peer using a multiaddress. Dial peer using a multiaddress.
@ -499,7 +499,7 @@ For example:
} }
``` ```
### `extern char* waku_disconnect_peer(char* peerId)` ### `extern char* waku_disconnect(char* peerId)`
Disconnect a peer using its peerID Disconnect a peer using its peerID

View File

@ -29,6 +29,7 @@ func main() {}
// - keepAliveInterval: interval in seconds to ping all peers // - keepAliveInterval: interval in seconds to ping all peers
// - relay: Enable WakuRelay. Default `true` // - relay: Enable WakuRelay. Default `true`
// - minPeersToPublish: The minimum number of peers required on a topic to allow broadcasting a message. Default `0` // - minPeersToPublish: The minimum number of peers required on a topic to allow broadcasting a message. Default `0`
// - filter: Enable Filter. Default `false`
func waku_new(configJSON *C.char) *C.char { func waku_new(configJSON *C.char) *C.char {
response := mobile.NewNode(C.GoString(configJSON)) response := mobile.NewNode(C.GoString(configJSON))
return C.CString(response) return C.CString(response)

View File

@ -19,6 +19,8 @@ var (
ChaChaPoly = WakuNoiseProtocolID(30) ChaChaPoly = WakuNoiseProtocolID(30)
) )
const NoisePaddingBlockSize = 248
var ErrorHandshakeComplete = errors.New("handshake complete") var ErrorHandshakeComplete = errors.New("handshake complete")
// All protocols share same cipher suite // All protocols share same cipher suite
@ -121,8 +123,13 @@ func (hs *Handshake) Step(readPayloadV2 *PayloadV2, transportMessage []byte) (*H
// We initialize a payload v2 and we set proper protocol ID (if supported) // We initialize a payload v2 and we set proper protocol ID (if supported)
result.Payload2.ProtocolId = hs.protocolID result.Payload2.ProtocolId = hs.protocolID
payload, err := PKCS7_Pad(transportMessage, NoisePaddingBlockSize)
if err != nil {
return nil, err
}
var noisePubKeys [][]byte var noisePubKeys [][]byte
msg, cs1, cs2, err = hs.state.WriteMessageAndGetPK(hs.hsBuff, &noisePubKeys, transportMessage) msg, cs1, cs2, err = hs.state.WriteMessageAndGetPK(hs.hsBuff, &noisePubKeys, payload)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -149,8 +156,14 @@ func (hs *Handshake) Step(readPayloadV2 *PayloadV2, transportMessage []byte) (*H
hs.shouldWrite = true hs.shouldWrite = true
// We retrieve and store the (decrypted) received transport message // We retrieve, and store the (unpadded decrypted) received transport message
result.TransportMessage = msg
payload, err := PKCS7_Unpad(msg, NoisePaddingBlockSize)
if err != nil {
return nil, err
}
result.TransportMessage = payload
} }
if cs1 != nil && cs2 != nil { if cs1 != nil && cs2 != nil {
@ -186,9 +199,12 @@ func (hs *Handshake) Encrypt(plaintext []byte) (*PayloadV2, error) {
return nil, errors.New("tried to encrypt empty plaintext") return nil, errors.New("tried to encrypt empty plaintext")
} }
// TODO: add padding (?) paddedTransportMessage, err := PKCS7_Pad(plaintext, NoisePaddingBlockSize)
if err != nil {
return nil, err
}
cyphertext, err := hs.enc.Encrypt(nil, nil, plaintext) cyphertext, err := hs.enc.Encrypt(nil, nil, paddedTransportMessage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -215,7 +231,12 @@ func (hs *Handshake) Decrypt(payload *PayloadV2) ([]byte, error) {
return nil, errors.New("tried to decrypt empty ciphertext") return nil, errors.New("tried to decrypt empty ciphertext")
} }
return hs.dec.Decrypt(nil, nil, payload.TransportMessage) paddedMessage, err := hs.dec.Decrypt(nil, nil, payload.TransportMessage)
if err != nil {
return nil, err
}
return PKCS7_Unpad(paddedMessage, NoisePaddingBlockSize)
} }
// NewHandshake_XX_25519_ChaChaPoly_SHA256 creates a handshake where the initiator and receiver are not aware of each other static keys // NewHandshake_XX_25519_ChaChaPoly_SHA256 creates a handshake where the initiator and receiver are not aware of each other static keys

View File

@ -186,3 +186,18 @@ func TestNoiseXK1HandshakeRoundtrip(t *testing.T) {
handshakeTest(t, hsAlice, hsBob) handshakeTest(t, hsAlice, hsBob)
} }
func TestPKCSPaddingUnpadding(t *testing.T) {
maxMessageLength := 3 * NoisePaddingBlockSize
for messageLen := 0; messageLen <= maxMessageLength; messageLen++ {
message := generateRandomBytes(t, messageLen)
padded, err := PKCS7_Pad(message, NoisePaddingBlockSize)
require.NoError(t, err)
unpadded, err := PKCS7_Unpad(padded, NoisePaddingBlockSize)
require.NoError(t, err)
require.Greater(t, len(padded), 0)
require.Equal(t, len(padded)%NoisePaddingBlockSize, 0)
require.Equal(t, message, unpadded)
}
}

48
waku/v2/noise/padding.go Normal file
View File

@ -0,0 +1,48 @@
package noise
import (
"errors"
)
// PKCS7_Pad pads a payload according to PKCS#7 as per
// RFC 5652 https://datatracker.ietf.org/doc/html/rfc5652#section-6.3
func PKCS7_Pad(payload []byte, paddingSize int) ([]byte, error) {
if paddingSize >= 256 {
return nil, errors.New("invalid padding size")
}
k := paddingSize - (len(payload) % paddingSize)
var padVal int
if k != 0 {
padVal = k
} else {
padVal = paddingSize
}
padding := make([]byte, padVal)
for i := range padding {
padding[i] = byte(padVal)
}
return append(payload, padding...), nil
}
// PKCS7_Unpad unpads a payload according to PKCS#7 as per
// RFC 5652 https://datatracker.ietf.org/doc/html/rfc5652#section-6.3
func PKCS7_Unpad(payload []byte, paddingSize int) ([]byte, error) {
if paddingSize >= 256 {
return nil, errors.New("invalid padding size")
}
if len(payload) == 0 {
return nil, nil // empty payload
}
high := len(payload) - 1
k := payload[high]
unpadded := payload[0:(high + 1 - int(k))]
return unpadded, nil
}

View File

@ -190,6 +190,6 @@ func (c *CodecRequest) writeServerResponse(w http.ResponseWriter, status int, re
_, _ = w.Write(b) _, _ = w.Write(b)
} else { } else {
// Not sure in which case will this happen. But seems harmless. // Not sure in which case will this happen. But seems harmless.
rpc.WriteError(w, 400, err.Error()) rpc.WriteError(w, status, err.Error())
} }
} }