Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base45 to a Set up payload #164

Merged
merged 2 commits into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/setup_payload/Base45.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@

#include "Base45.h"

#include <iostream>

using namespace std;

namespace chip {

static const int kBase45ChunkLen = 3;
static const int kBytesChunkLen = 2;

string base45Encode(const uint8_t * buf, size_t buf_len)
{
Expand All @@ -46,7 +49,8 @@ string base45Encode(const uint8_t * buf, size_t buf_len)

// eat little-endian uint16_ts from the byte array
// encode as 3 base45 characters
while (buf_len >= 2)

while (buf_len >= kBytesChunkLen)
{
int next = buf[0] + buf[1] * 256;

Expand All @@ -55,8 +59,8 @@ string base45Encode(const uint8_t * buf, size_t buf_len)
result += codes[next % radix];
next /= radix;
}
buf += 2;
buf_len -= 2;
buf += kBytesChunkLen;
buf_len -= kBytesChunkLen;
}
// handle leftover byte, if any
if (buf_len != 0)
Expand Down Expand Up @@ -156,6 +160,7 @@ CHIP_ERROR base45Decode(string base45, vector<uint8_t> & result)
// base45 characters
if (base45.length() % kBase45ChunkLen == 1)
{
fprintf(stderr, "\nFailed decoding base45. Input was too short. %lu", base45.length());
return CHIP_ERROR_INVALID_MESSAGE_LENGTH;
}
result.clear();
Expand Down
13 changes: 11 additions & 2 deletions src/setup_payload/QRCodeSetupPayloadGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static void populateBits(uint8_t * bits, int & offset, uint64_t input, size_t nu
// do nothing in the case where we've overflowed. should never happen
if (offset + numberOfBits > kTotalPayloadDataSizeInBits || input >= 1u << numberOfBits)
{
fprintf(stderr, "Overflow while trying to generate a QR Code. Bailing.");
return;
}

Expand Down Expand Up @@ -86,7 +87,11 @@ string QRCodeSetupPayloadGenerator::payloadBinaryRepresentation()
}
return binary;
}
return string();
else
{
fprintf(stderr, "\nFailed encoding invalid payload\n");
return string();
}
}

string QRCodeSetupPayloadGenerator::payloadBase45Representation()
Expand All @@ -99,5 +104,9 @@ string QRCodeSetupPayloadGenerator::payloadBase45Representation()

return base45Encode(bits, sizeof(bits) / sizeof(bits[0]));
}
return string();
else
{
fprintf(stderr, "\nFailed encoding invalid payload\n");
return string();
}
}
1 change: 0 additions & 1 deletion src/setup_payload/QRCodeSetupPayloadGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

#include "SetupPayload.h"

#include <bitset>
#include <string>
using namespace std;

Expand Down
80 changes: 80 additions & 0 deletions src/setup_payload/QRCodeSetupPayloadParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
*
* <COPYRIGHT>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @file
* This file describes a QRCode Setup Payload parser based on the
* CHIP specification.
*/

#include "QRCodeSetupPayloadParser.h"
#include "Base45.h"

#include <iostream>
#include <vector>

using namespace chip;
using namespace std;

// Populate numberOfBits into dest from buf starting at startIndex
static uint64_t readBits(vector<uint8_t> buf, int & index, size_t numberOfBitsToRead)
{
uint64_t dest = 0;
if (index + numberOfBitsToRead > buf.size() * 8 || numberOfBitsToRead > sizeof(uint64_t) * 8)
{
fprintf(stderr, "Error parsing QR code. startIndex %d numberOfBitsToLoad %zu buf_len %zu ", index, numberOfBitsToRead,
buf.size());
return 0;
bhaskar-apple marked this conversation as resolved.
Show resolved Hide resolved
}

int currentIndex = index;
for (size_t bitsRead = 0; bitsRead < numberOfBitsToRead; bitsRead++)
{
if (buf[currentIndex / 8] & (1 << (currentIndex % 8)))
{
dest |= (1 << bitsRead);
}
currentIndex++;
}
index += numberOfBitsToRead;
return dest;
}

SetupPayload QRCodeSetupPayloadParser::payload()
bhaskar-apple marked this conversation as resolved.
Show resolved Hide resolved
{
vector<uint8_t> buf = vector<uint8_t>();

if (CHIP_NO_ERROR != base45Decode(mBase45StringRepresentation, buf))
{
fprintf(stderr, "Decoding of base45 string failed");
return SetupPayload();
}

SetupPayload payload;

int indexToReadFrom = 0;

payload.version = readBits(buf, indexToReadFrom, kVersionFieldLengthInBits);
payload.vendorID = readBits(buf, indexToReadFrom, kVendorIDFieldLengthInBits);
payload.productID = readBits(buf, indexToReadFrom, kProductIDFieldLengthInBits);
payload.requiresCustomFlow = readBits(buf, indexToReadFrom, kCustomFlowRequiredFieldLengthInBits);
payload.rendezvousInformation = readBits(buf, indexToReadFrom, kRendezvousInfoFieldLengthInBits);
payload.discriminator = readBits(buf, indexToReadFrom, kPayloadDiscriminatorFieldLengthInBits);
payload.setUpPINCode = readBits(buf, indexToReadFrom, kSetupPINCodeFieldLengthInBits);

return payload;
}
46 changes: 46 additions & 0 deletions src/setup_payload/QRCodeSetupPayloadParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
*
* <COPYRIGHT>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @file
* This file describes a QRCode Setup Payload parser based on the
* CHIP specification.
*/

#include "SetupPayload.h"

#include <string>
using namespace std;

namespace chip
{

/**
* @class QRCodeSetupPayloadParser
* A class that can be used to convert a base45 encoded payload to a SetupPayload object
* */
class QRCodeSetupPayloadParser
{
private:
string mBase45StringRepresentation;
bhaskar-apple marked this conversation as resolved.
Show resolved Hide resolved

public:
QRCodeSetupPayloadParser(string base45Representation) : mBase45StringRepresentation(base45Representation){};
SetupPayload payload();
};

}; // namespace chip
14 changes: 10 additions & 4 deletions src/setup_payload/SetupPayload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,20 @@ bool SetupPayload::isValid()
{
return false;
}
// make sure the rendezvousInformation only uses allowed values
// i.e it must be > 0 and set to 1 or a power of 2.
bhaskar-apple marked this conversation as resolved.
Show resolved Hide resolved
uint16_t rezInfo = rendezvousInformation;
if (rezInfo == 0 || (rezInfo != 1 && (rezInfo & (rezInfo - 1)) != 0))

if (version == 0 && rendezvousInformation == 0 && discriminator == 0 && setUpPINCode == 0)
{
return false;
}

return true;
}

bool SetupPayload::operator==(const SetupPayload & input)
{
return this->version == input.version && this->vendorID == input.vendorID && this->productID == input.productID &&
this->requiresCustomFlow == input.requiresCustomFlow && this->rendezvousInformation == input.rendezvousInformation &&
this->discriminator == input.discriminator && this->setUpPINCode == input.setUpPINCode;
}

} // namespace chip
7 changes: 7 additions & 0 deletions src/setup_payload/SetupPayload.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#define _SETUP_PAYLOAD_H_

#include <stdint.h>
#include <string>

using namespace std;

namespace chip {
// TODO this shuould point to the spec
Expand Down Expand Up @@ -55,7 +58,11 @@ class SetupPayload
uint32_t setUpPINCode;

// Test that the Setup Payload is within expected value ranges
SetupPayload() :
version(0), vendorID(0), productID(0), requiresCustomFlow(0), rendezvousInformation(0), discriminator(0), setUpPINCode(0){};

bool isValid();
bool operator==(const SetupPayload & input);
};

}; // namespace chip
Expand Down
2 changes: 1 addition & 1 deletion src/setup_payload/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ TESTS_ENVIRONMENT = \
# Source, compiler, and linker options for test programs.

TestQrCode_LDADD = $(COMMON_LDADD)
TestQrCode_SOURCES = tests.cpp
TestQrCode_SOURCES = tests_qrcode.cpp

if CHIP_BUILD_COVERAGE
CLEANFILES = $(wildcard *.gcda *.gcno)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "SetupPayload.cpp"
#include "Base45.cpp"
#include "QRCodeSetupPayloadGenerator.cpp"
#include "QRCodeSetupPayloadParser.cpp"

using namespace chip;
using namespace std;
Expand Down Expand Up @@ -154,7 +155,7 @@ int testSetupPayloadVerify()

// test invalid rendezvousInformation
test_payload = payload;
test_payload.rendezvousInformation = 3;
test_payload.rendezvousInformation = 512;
surprises += EXPECT_EQ(test_payload.isValid(), false);

// test invalid discriminator
Expand All @@ -170,7 +171,104 @@ int testSetupPayloadVerify()
return surprises;
}

int testInvalidQRCodePayload_WrongCharacterSet()
{
int surprises = 0;
string invalidString = "adas12AA";
QRCodeSetupPayloadParser parser = QRCodeSetupPayloadParser(invalidString);
SetupPayload payload = parser.payload();

surprises = EXPECT_EQ(payload.isValid(), false);
return surprises;
}

int testInvalidQRCodePayload_WrongLength()
bhaskar-apple marked this conversation as resolved.
Show resolved Hide resolved
{
int surprises = 0;
string invalidString = "AA12";
QRCodeSetupPayloadParser parser = QRCodeSetupPayloadParser(invalidString);
SetupPayload payload = parser.payload();

surprises = EXPECT_EQ(payload.isValid(), false);
return surprises;
}

int testPayloadEquality()
{
SetupPayload payload;

payload.version = 5;
payload.vendorID = 12;
payload.productID = 1;
payload.requiresCustomFlow = 0;
payload.rendezvousInformation = 1;
payload.discriminator = 128;
payload.setUpPINCode = 2048;

SetupPayload equalPayload;
equalPayload.version = 5;
equalPayload.vendorID = 12;
equalPayload.productID = 1;
equalPayload.requiresCustomFlow = 0;
equalPayload.rendezvousInformation = 1;
equalPayload.discriminator = 128;
equalPayload.setUpPINCode = 2048;

bool result = payload == equalPayload;
return EXPECT_EQ(result, true);
}

int testPayloadInEquality()
{
SetupPayload payload;

payload.version = 5;
payload.vendorID = 12;
payload.productID = 1;
payload.requiresCustomFlow = 0;
payload.rendezvousInformation = 1;
payload.discriminator = 128;
payload.setUpPINCode = 2048;

SetupPayload unequalPayload;
unequalPayload.version = 5;
unequalPayload.vendorID = 12;
unequalPayload.productID = 1;
unequalPayload.requiresCustomFlow = 0;
unequalPayload.rendezvousInformation = 1;
unequalPayload.discriminator = 28;
unequalPayload.setUpPINCode = 121233;

bool result = payload == unequalPayload;
return EXPECT_EQ(result, false);
}

int testQRCodeToPayloadGeneration()
{
int surprises = 0;
SetupPayload payload;
payload.version = 3;
payload.vendorID = 100;
payload.productID = 12;
payload.requiresCustomFlow = 1;
payload.rendezvousInformation = 4;
payload.discriminator = 233;
payload.setUpPINCode = 5221133;

QRCodeSetupPayloadGenerator generator(payload);
string base45Rep = generator.payloadBase45Representation();

QRCodeSetupPayloadParser parser(base45Rep);
SetupPayload resultingPayload = parser.payload();

bool result = payload == resultingPayload;
surprises += EXPECT_EQ(result, true);
return surprises;
}

int main(int argc, char ** argv)
{
return testBitsetLen() + testPayloadByteArrayRep() + testPayloadBase45Rep() + testBase45() + testSetupPayloadVerify();
return testBitsetLen() + testPayloadByteArrayRep() + testPayloadBase45Rep() + testBase45() + testSetupPayloadVerify() +
testPayloadEquality() + testPayloadInEquality() + testQRCodeToPayloadGeneration() +
testInvalidQRCodePayload_WrongCharacterSet() + testInvalidQRCodePayload_WrongLength();
}