|
| 1 | +package com.juul.koap |
| 2 | + |
| 3 | +import com.juul.koap.Message.Option.Oscore |
| 4 | + |
| 5 | +private val PARTIAL_IV_LENGTH_RANGE = 0..5 |
| 6 | +private const val PARTIAL_IV_LENGTH_MASK = 0x07 |
| 7 | +private const val KID_FLAG = 0x08 |
| 8 | +private const val KID_CONTEXT_FLAG = 0x10 |
| 9 | + |
| 10 | +/** |
| 11 | + * Creates a binary OSCORE option value from an Oscore option object. |
| 12 | + * |
| 13 | + * - [RFC 8613](https://tools.ietf.org/html/rfc8613#section-2) 2. The OSCORE Option |
| 14 | + * - [RFC 8613](https://tools.ietf.org/html/rfc8613#section-6.1) 6.1. Encoding of the OSCORE Option Value |
| 15 | + */ |
| 16 | +internal fun oscoreOptionValue(oscore: Oscore): ByteArray { |
| 17 | + val partialIvLength = oscore.partialIv.size |
| 18 | + require(partialIvLength in PARTIAL_IV_LENGTH_RANGE) { |
| 19 | + "Partial IV length of $partialIvLength is outside allowable range of $PARTIAL_IV_LENGTH_RANGE" |
| 20 | + } |
| 21 | + val kidContextLength = if (oscore.kidContext != null) oscore.kidContext.size else 0 |
| 22 | + val kidFlagBit = if (oscore.kid != null) KID_FLAG else 0 |
| 23 | + val kidContextFlagBit = if (oscore.kidContext != null) KID_CONTEXT_FLAG else 0 |
| 24 | + val flagBits = partialIvLength or kidFlagBit or kidContextFlagBit |
| 25 | + if (flagBits == 0) { |
| 26 | + // If the OSCORE flag bits are all zero (0x00), the option value SHALL be empty |
| 27 | + return byteArrayOf() |
| 28 | + } |
| 29 | + var value = byteArrayOf(flagBits.toByte()) + oscore.partialIv |
| 30 | + if (oscore.kidContext != null) { |
| 31 | + value += kotlin.byteArrayOf(kidContextLength.toByte()) + oscore.kidContext |
| 32 | + } |
| 33 | + if (oscore.kid != null) { |
| 34 | + value += oscore.kid |
| 35 | + } |
| 36 | + return value |
| 37 | +} |
| 38 | + |
| 39 | +/** |
| 40 | + * Parses an Oscore option object from a binary OSCORE option value. |
| 41 | + */ |
| 42 | +internal fun oscoreFromOptionValue(value: ByteArray): Oscore { |
| 43 | + if (value.size == 0) { |
| 44 | + return Oscore(byteArrayOf(), null, null) |
| 45 | + } |
| 46 | + val flagBits = value[0].toInt() |
| 47 | + val partialIvLength = flagBits and PARTIAL_IV_LENGTH_MASK |
| 48 | + val kidFlag = (flagBits and KID_FLAG) != 0 |
| 49 | + val kidContextFlag = (flagBits and KID_CONTEXT_FLAG) != 0 |
| 50 | + val partialIv = value.sliceArray(1 until 1 + partialIvLength) |
| 51 | + val kidContextLength = if (kidContextFlag) value[1 + partialIvLength].toInt() else 0 |
| 52 | + val kidContext = if (kidContextFlag) { |
| 53 | + value.sliceArray(2 + partialIvLength until 2 + partialIvLength + kidContextLength) |
| 54 | + } else { |
| 55 | + null |
| 56 | + } |
| 57 | + val kidOffset = (if (kidContextFlag) 2 else 1) + partialIvLength + kidContextLength |
| 58 | + val kid = if (kidFlag) value.sliceArray(kidOffset until value.size) else null |
| 59 | + return Oscore(partialIv, kidContext, kid) |
| 60 | +} |
0 commit comments