Skip to content

Commit

Permalink
Merge pull request #164 from bhaskar-apple/BS-QRCodeParser
Browse files Browse the repository at this point in the history
Base45 to a Set up payload
  • Loading branch information
woody-apple authored Mar 31, 2020
2 parents 111f99c + 609ecb1 commit b19f044
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 14 deletions.
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
123 changes: 123 additions & 0 deletions src/setup_payload/QRCodeSetupPayloadParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
*
* <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 <core/CHIPError.h>
#include <iostream>
#include <vector>

using namespace chip;
using namespace std;

// Populate numberOfBits into dest from buf starting at startIndex
static CHIP_ERROR readBits(vector<uint8_t> buf, int & index, uint64_t & dest, size_t numberOfBitsToRead)
{
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 CHIP_ERROR_INVALID_ARGUMENT;
}

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 CHIP_NO_ERROR;
}

CHIP_ERROR QRCodeSetupPayloadParser::populatePayload(SetupPayload & outPayload)
{
vector<uint8_t> buf = vector<uint8_t>();

CHIP_ERROR result = base45Decode(mBase45Representation, buf);

if (CHIP_NO_ERROR != result)
{
fprintf(stderr, "Decoding of base45 string failed");
return result;
}

int indexToReadFrom = 0;
uint64_t dest;

result = readBits(buf, indexToReadFrom, dest, kVersionFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.version = dest;

result = readBits(buf, indexToReadFrom, dest, kVendorIDFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.vendorID = dest;

result = readBits(buf, indexToReadFrom, dest, kProductIDFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.productID = dest;

result = readBits(buf, indexToReadFrom, dest, kCustomFlowRequiredFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.requiresCustomFlow = dest;

result = readBits(buf, indexToReadFrom, dest, kRendezvousInfoFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.rendezvousInformation = dest;

result = readBits(buf, indexToReadFrom, dest, kPayloadDiscriminatorFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.discriminator = dest;

result = readBits(buf, indexToReadFrom, dest, kSetupPINCodeFieldLengthInBits);
if (result != CHIP_NO_ERROR)
{
return result;
}
outPayload.setUpPINCode = dest;

return result;
}
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 <core/CHIPError.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 mBase45Representation;

public:
QRCodeSetupPayloadParser(string base45Representation) : mBase45Representation(base45Representation){};
CHIP_ERROR populatePayload(SetupPayload & outPayload);
};

}; // 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.
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
Loading

0 comments on commit b19f044

Please sign in to comment.