use of org.openremote.agent.protocol.bluetooth.mesh.NetworkKey in project openremote by openremote.
the class BaseMeshNetwork method updateNetKey.
/**
* Update a network key in the mesh network.
*
* <p>
* Updating a NetworkKey's key value requires initiating a Key Refresh Procedure. A NetworkKey that's in use
* would require a Key Refresh Procedure to update it's key contents. However a NetworkKey that's not in could
* be updated without this procedure. If the key is in use, call {@link #distributeNetKey(NetworkKey, byte[])}
* to initiate the Key Refresh Procedure.
* </p>
*
* @param networkKey Network key
* @throws IllegalArgumentException if the key is already in use
*/
public synchronized boolean updateNetKey(final NetworkKey networkKey) throws IllegalArgumentException {
final int keyIndex = networkKey.getKeyIndex();
final NetworkKey key = getNetKey(keyIndex);
// This will return true only if the key index and the key are the same
if (key.equals(networkKey)) {
// The name might be updated so we must update the key.
return updateMeshKey(networkKey);
} else {
// If the keys are not the same we check if its in use before updating the key
if (!isKeyInUse(key)) {
// This will return true only if the key index and the key are the same
return updateMeshKey(networkKey);
} else {
throw new IllegalArgumentException("Unable to update a network key that's already in use.");
}
}
}
use of org.openremote.agent.protocol.bluetooth.mesh.NetworkKey in project openremote by openremote.
the class BaseMeshMessageHandler method parseMeshPduNotifications.
/**
* Parse the mesh network/proxy pdus
* <p>
* This method will try to network layer de-obfuscation and decryption using the available network keys
* </p>
*
* @param pdu mesh pdu that was sent
* @param network {@link MeshNetwork}
*/
protected synchronized void parseMeshPduNotifications(final byte[] pdu, final MeshNetwork network) throws ExtendedInvalidCipherTextException {
final List<NetworkKey> networkKeys = network.getNetKeys();
final int ivi = ((pdu[1] & 0xFF) >>> 7) & 0x01;
final int nid = pdu[1] & 0x7F;
final int acceptedIvIndex = network.getIvIndex().getIvIndex();
int ivIndex = acceptedIvIndex == 0 ? 0 : acceptedIvIndex - 1;
int tempIvIndex = ivIndex;
NetworkKey networkKey = null;
SecureUtils.K2Output k2Output = null;
byte[] networkHeader = null;
int ctlTtl = 0;
int ctl = 0;
int src = 0;
ProvisionedMeshNode node = null;
while (tempIvIndex <= ivIndex + 1) {
// Here we go through all the network keys and filter out network keys based on the nid.
for (int i = 0; i < networkKeys.size(); i++) {
networkKey = networkKeys.get(i);
k2Output = getMatchingK2Output(networkKey, nid);
if (k2Output != null) {
networkHeader = deObfuscateNetworkHeader(pdu, MeshParserUtils.intToBytes(tempIvIndex), k2Output.getPrivacyKey());
ctlTtl = networkHeader[0];
ctl = (ctlTtl >> 7) & 0x01;
src = MeshParserUtils.unsignedBytesToInt(networkHeader[5], networkHeader[4]);
// Check if the src is known to the network and if found let's break
// Note a node may not be found if there are two provisioners are operating independently without syncing the network.
node = network.getNode(src);
if (node != null) {
break;
}
}
}
// IF the node was found we can safely try to decrypt message with the network key which we found src of the message.
if (node != null && k2Output != null) {
final byte[] sequenceNumber = ByteBuffer.allocate(3).order(ByteOrder.BIG_ENDIAN).put(networkHeader, 1, 3).array();
LOG.info("Sequence number of received Network PDU: " + MeshParserUtils.convert24BitsToInt(sequenceNumber));
// TODO validate ivi
byte[] nonce;
try {
final int networkPayloadLength = pdu.length - (2 + networkHeader.length);
final byte[] transportPdu = new byte[networkPayloadLength];
System.arraycopy(pdu, 8, transportPdu, 0, networkPayloadLength);
final byte[] decryptedPayload;
final MeshMessageState state;
if (pdu[0] == MeshManagerApi.PDU_TYPE_NETWORK) {
nonce = createNetworkNonce((byte) ctlTtl, sequenceNumber, src, MeshParserUtils.intToBytes(tempIvIndex));
decryptedPayload = SecureUtils.decryptCCM(transportPdu, k2Output.getEncryptionKey(), nonce, SecureUtils.getNetMicLength(ctl));
state = getState(src);
} else {
nonce = createProxyNonce(sequenceNumber, src, MeshParserUtils.intToBytes(tempIvIndex));
decryptedPayload = SecureUtils.decryptCCM(transportPdu, k2Output.getEncryptionKey(), nonce, SecureUtils.getNetMicLength(ctl));
state = getState(MeshAddress.UNASSIGNED_ADDRESS);
}
if (state != null) {
// TODO look in to proxy filter messages
((DefaultNoOperationMessageState) state).parseMeshPdu(networkKey, node, pdu, networkHeader, decryptedPayload, tempIvIndex, sequenceNumber);
return;
}
} catch (InvalidCipherTextException ex) {
throw new ExtendedInvalidCipherTextException(ex.getMessage(), ex.getCause(), BaseMeshMessageHandler.class.getName());
}
}
tempIvIndex++;
}
}
Aggregations