def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() der = Blob(base64.b64decode(base64Content), False) # Decode the PKCS #8 key to get the algorithm OID. parsedNode = DerNode.parse(der.buf(), 0) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren() oidString = algorithmIdChildren[0].toVal() privateKey = serialization.load_der_private_key( der.toBytes(), password=None, backend=default_backend()) # Sign the data. data = Blob(data, False).toBytes() if (oidString == PublicKey.RSA_ENCRYPTION_OID or oidString == PublicKey.EC_ENCRYPTION_OID): if oidString == PublicKey.RSA_ENCRYPTION_OID: signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256()) else: signer = privateKey.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() return Blob(bytearray(signature), False) else: raise SecurityException( "FilePrivateKeyStorage.sign: Unrecognized private key type")
def sign(self, data, keyName, digestAlgorithm = DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() der = Blob(base64.b64decode(base64Content), False) # Decode the PKCS #8 key to get the algorithm OID. parsedNode = DerNode.parse(der.buf(), 0) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren() oidString = algorithmIdChildren[0].toVal() privateKey = serialization.load_der_private_key( der.toBytes(), password = None, backend = default_backend()) # Sign the data. data = Blob(data, False).toBytes() if (oidString == PublicKey.RSA_ENCRYPTION_OID or oidString == PublicKey.EC_ENCRYPTION_OID): if oidString == PublicKey.RSA_ENCRYPTION_OID: signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256()) else: signer = privateKey.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() return Blob(bytearray(signature), False) else: raise SecurityException( "FilePrivateKeyStorage.sign: Unrecognized private key type")
def _decode(encoding): """ Decode the IBLT from the Blob. This converts the Blob into a uint8_t array which is then decoded to a uint32_t array. :param Blob encoding: The encoded IBLT. :return: A uint32_t array representing the hash table of the IBLT. :rtype: Array<int> """ # Use Blob to convert bytes to an integer array. ibltValues = Blob(zlib.decompress(encoding.toBytes()), False) nEntries = int(len(ibltValues) / 4) values = [0] * nEntries ibltValuesBuf = ibltValues.buf() for i in range(0, 4 * nEntries, 4): t = ((ibltValuesBuf[i + 3] << 24) + (ibltValuesBuf[i + 2] << 16) + (ibltValuesBuf[i + 1] << 8) + ibltValuesBuf[i]) values[int(i / 4)] = t return values
class Component(object): """ Create a new Name.Component with a copy of the given value. (To create an ImplicitSha256Digest component, use fromImplicitSha256Digest.) :param value: (optional) If value is already a Blob or Name.Component, then take another pointer to the value. Otherwise, create a new Blob with a copy of the value. If omitted, create an empty component. :type value: Blob or Name.Component or value for Blob constructor :param int type: (optional) The component type as an int from the ComponentType enum. If name component type is not a recognized ComponentType enum value, then set this to ComponentType.OTHER_CODE and use the otherTypeCode parameter. If omitted, use ComponentType.GENERIC. :param int otherTypeCode: (optional) If type is ComponentType.OTHER_CODE, then this is the packet's unrecognized content type code, which must be non-negative. """ def __init__(self, value=None, type=None, otherTypeCode=None): if isinstance(value, Name.Component): # Copy constructor. Use the existing Blob in the other Component. self._value = value._value self._type = value._type self._otherTypeCode = value._otherTypeCode return if value == None: self._value = Blob([]) else: # Blob will make a copy. self._value = value if isinstance(value, Blob) else Blob(value) if type == ComponentType.OTHER_CODE: if otherTypeCode == None: raise ValueError( "To use an other code, call Name.Component(value, ComponentType.OTHER_CODE, otherTypeCode)" ) if otherTypeCode < 0: raise ValueError( "Name.Component other type code must be non-negative") self._otherTypeCode = otherTypeCode else: self._otherTypeCode = -1 self._type = ComponentType.GENERIC if type == None else type def getValue(self): """ Get the value of the component. :return: The component value. :rtype: Blob """ return self._value def getType(self): """ Get the name component type. :return: The name component type as an int from the ComponentType enum. If this is ComponentType.OTHER_CODE, then call getOtherTypeCode() to get the unrecognized component type code. :rtype: int """ return self._type def getOtherTypeCode(self): """ Get the component type code from the packet which is other than a recognized ComponentType enum value. This is only meaningful if getType() is ComponentType.OTHER_CODE. :return: The type code. :rtype: int """ return self._otherTypeCode def toEscapedString(self, result=None): """ Convert this component to a string, escaping characters according to the NDN URI Scheme. This also adds "..." to a value with zero or more ".". This adds a type code prefix as needed, such as "sha256digest=". :param BytesIO result: (optional) The BytesIO stream to write to. If omitted, return a str with the result. :return: The result as a string (only if result is omitted). :rtype: str """ if result == None: result = BytesIO() self.toEscapedString(result) return Common.getBytesIOString(result) if self._type == ComponentType.IMPLICIT_SHA256_DIGEST: result.write("sha256digest=".encode('utf-8')) self._value.toHex(result) return if self._type != ComponentType.GENERIC: result.write( str(self._otherTypeCode) if self._type == ComponentType.OTHER_CODE else str(self._type)) result.write("=") Name.toEscapedString(self._value.buf(), result) def isSegment(self): """ Check if this component is a segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a segment number. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0x00 and self.isGeneric()) def isSegmentOffset(self): """ Check if this component is a segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a segment byte offset. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFB and self.isGeneric()) def isVersion(self): """ Check if this component is a version number according to NDN naming conventions for "Versioning" (marker 0xFD). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a version number. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFD and self.isGeneric()) def isTimestamp(self): """ Check if this component is a timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a timestamp. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFC and self.isGeneric()) def isSequenceNumber(self): """ Check if this component is a sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a sequence number. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFE and self.isGeneric()) def isGeneric(self): """ Check if this component is a generic component. :return: True if this is an generic component. :rtype: bool """ return self._type == ComponentType.GENERIC def isImplicitSha256Digest(self): """ Check if this component is an ImplicitSha256Digest component. :return: True if this is an ImplicitSha256Digest component. :rtype: bool """ return self._type == ComponentType.IMPLICIT_SHA256_DIGEST def toNumber(self): """ Interpret this name component as a network-ordered number and return an integer. :return: The integer number. :rtype: int """ result = 0 for i in range(self._value.size()): result *= 256 result += self._value.buf()[i] return result def toNumberWithMarker(self, marker): """ Interpret this name component as a network-ordered number with a marker and return an integer. :param int marker: The required first byte of the component. :return: The integer number. :rtype: int :raises RuntimeError: If the first byte of the component does not equal the marker. """ if self._value.size() <= 0 or self._value.buf()[0] != marker: raise RuntimeError( "Name component does not begin with the expected marker") result = 0 for i in range(1, self._value.size()): result *= 256 result += self._value.buf()[i] return result def toSegment(self): """ Interpret this name component as a segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer segment number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0x00) def toSegmentOffset(self): """ Interpret this name component as a segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer segment byte offset. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFB) def toVersion(self): """ Interpret this name component as a version number according to NDN naming conventions for "Versioning" (marker 0xFD). Note that this returns the exact number from the component without converting it to a time representation. http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer version number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFD) def toTimestamp(self): """ Interpret this name component as a timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The number of microseconds since the UNIX epoch (Thursday, 1 January 1970) not counting leap seconds. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFC) def toSequenceNumber(self): """ Interpret this name component as a sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer sequence number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFE) def equals(self, other): """ Check if this is the same component as other. :param Name.Component other: The other Component to compare with. :return: True if the components are equal, otherwise False. :rtype: bool """ if self._type == ComponentType.OTHER_CODE: return (self._value.equals(other._value) and other._type == ComponentType.OTHER_CODE and self._otherTypeCode == other._otherTypeCode) else: return self._value.equals( other._value) and self._type == other._type def compare(self, other): """ Compare this to the other Component using NDN canonical ordering. :param Name.Component other: The other Component to compare with. :return: 0 If they compare equal, -1 if self comes before other in the canonical ordering, or 1 if self comes after other in the canonical ordering. :rtype: int :see: http://named-data.net/doc/0.2/technical/CanonicalOrder.html """ myTypeCode = (self._otherTypeCode if self._type == ComponentType.OTHER_CODE else self._type) otherTypeCode = (other._otherTypeCode if other._type == ComponentType.OTHER_CODE else other._type) if myTypeCode < otherTypeCode: return -1 if myTypeCode > otherTypeCode: return 1 if self._value.size() < other._value.size(): return -1 if self._value.size() > other._value.size(): return 1 # The components are equal length. Just do a byte compare. return self._value.compare(other._value) @staticmethod def fromNumber(number, type=None, otherTypeCode=None): """ Create a component whose value is the nonNegativeInteger encoding of the number. :param int number: The number to be encoded. :param int type: (optional) The component type as an int from the ComponentType enum. If name component type is not a recognized ComponentType enum value, then set this to ComponentType.OTHER_CODE and use the otherTypeCode parameter. If omitted, use ComponentType.GENERIC. :param int otherTypeCode: (optional) If type is ComponentType.OTHER_CODE, then this is the packet's unrecognized content type code, which must be non-negative. :return: The new component value. :rtype: Name.Component """ encoder = TlvEncoder(8) encoder.writeNonNegativeInteger(number) return Name.Component(Blob(encoder.getOutput(), False), type, otherTypeCode) @staticmethod def fromNumberWithMarker(number, marker): """ Create a component whose value is the marker appended with the nonNegativeInteger encoding of the number. :param int number: The number to be encoded. :param int marker: The marker to use as the first byte of the component. :return: The component value. :rtype: Name.Component """ encoder = TlvEncoder(9) # Encode backwards. encoder.writeNonNegativeInteger(number) encoder.writeNonNegativeInteger(marker) return Name.Component(Blob(encoder.getOutput(), False)) @staticmethod def fromSegment(segment): """ Create a component with the encoded segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int segment: The segment number. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(segment, 0x00) @staticmethod def fromSegmentOffset(segmentOffset): """ Create a component with the encoded segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int segmentOffset: The segment byte offset. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(segmentOffset, 0xFB) @staticmethod def fromVersion(version): """ Create a component with the encoded version number according to NDN naming conventions for "Versioning" (marker 0xFD). http://named-data.net/doc/tech-memos/naming-conventions.pdf Note that this encodes the exact value of version without converting from a time representation. :param int version: The version number. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(version, 0xFD) @staticmethod def fromTimestamp(timestamp): """ Create a component with the encoded timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int timestamp: The number of microseconds since the UNIX epoch (Thursday, 1 January 1970) not counting leap seconds. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(timestamp, 0xFC) @staticmethod def fromSequenceNumber(sequenceNumber): """ Create a component with the encoded sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int sequenceNumber: The sequence number. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(sequenceNumber, 0xFE) @staticmethod def fromImplicitSha256Digest(digest): """ Create a component of type ImplicitSha256DigestComponent, so that isImplicitSha256Digest() is true. :param digest: The SHA-256 digest value. :type digest: Blob or value for Blob constructor :return: The new Component. :rtype: Name.Component :raises RuntimeError: If the digest length is not 32 bytes. """ digestBlob = digest if isinstance(digest, Blob) else Blob(digest) if digestBlob.size() != 32: raise RuntimeError( "Name.Component.fromImplicitSha256Digest: The digest length must be 32 bytes" ) result = Name.Component(digestBlob) result._type = ComponentType.IMPLICIT_SHA256_DIGEST return result def getSuccessor(self): """ Get the successor of this component, as described in Name.getSuccessor. :return: A new Name.Component which is the successor of this. :rtype: Name.Component """ # Allocate an extra byte in case the result is larger. result = bytearray(self._value.size() + 1) carry = True for i in range(self._value.size() - 1, -1, -1): if carry: result[i] = (self._value.buf()[i] + 1) & 0xff carry = (result[i] == 0) else: result[i] = self._value.buf()[i] if carry: # Assume all the bytes were set to zero (or the component was # empty). In NDN ordering, carry does not mean to prepend a 1, # but to make a component one byte longer of all zeros. result[len(result) - 1] = 0 else: # We didn't need the extra byte. result = result[0:self._value.size()] return Name.Component(Blob(result, False), self._type, self._otherTypeCode) # Python operators def __eq__(self, other): return isinstance(other, Name.Component) and self.equals(other) def __ne__(self, other): return not self == other def __le__(self, other): return self.compare(other) <= 0 def __lt__(self, other): return self.compare(other) < 0 def __ge__(self, other): return self.compare(other) >= 0 def __gt__(self, other): return self.compare(other) > 0 def __len__(self): return self._value.size() def __str__(self): return self.toEscapedString() def __hash__(self): return (37 * (self._otherTypeCode if self._type == ComponentType.OTHER_CODE else self._type) + hash(self._value))
class Component(object): """ Create a new GENERIC Name.Component. :param value: (optional) If value is already a Blob or Name.Component, then take another pointer to the value. Otherwise, create a new Blob with a copy of the value. If omitted, create an empty component. :type value: Blob or Name.Component or value for Blob constructor """ def __init__(self, value = None): if type(value) is Name.Component: # Copy constructor. Use the existing Blob in the other Component. self._value = value._value self._type = value._type return if value == None: self._value = Blob([]) else: # Blob will make a copy. self._value = value if isinstance(value, Blob) else Blob(value) self._type = Name.Component.ComponentType.GENERIC class ComponentType(object): """ A Name.Component.ComponentType specifies the recognized types of a name component. """ IMPLICIT_SHA256_DIGEST = 1 GENERIC = 8 def getValue(self): """ Get the value of the component. :return: The component value. :rtype: Blob """ return self._value def toEscapedString(self, result = None): """ Convert this component to a string, escaping characters according to the NDN URI Scheme. This also adds "..." to a value with zero or more ".". This adds a type code prefix as needed, such as "sha256digest=". :param BytesIO result: (optional) The BytesIO stream to write to. If omitted, return a str with the result. :return: The result as a string (only if result is omitted). :rtype: str """ if result == None: result = BytesIO() self.toEscapedString(result) return Common.getBytesIOString(result) else: if self._type == Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST: result.write("sha256digest=".encode('utf-8')) self._value.toHex(result) else: Name.toEscapedString(self._value.buf(), result) def isSegment(self): """ Check if this component is a segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a segment number. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0x00 and self.isGeneric()) def isSegmentOffset(self): """ Check if this component is a segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a segment byte offset. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFB and self.isGeneric()) def isVersion(self): """ Check if this component is a version number according to NDN naming conventions for "Versioning" (marker 0xFD). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a version number. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFD and self.isGeneric()) def isTimestamp(self): """ Check if this component is a timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a timestamp. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFC and self.isGeneric()) def isSequenceNumber(self): """ Check if this component is a sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: True if this is a sequence number. :rtype: bool """ return (self._value.size() >= 1 and self._value.buf()[0] == 0xFE and self.isGeneric()) def isGeneric(self): """ Check if this component is a generic component. :return: True if this is an generic component. :rtype: bool """ return self._type == Name.Component.ComponentType.GENERIC def isImplicitSha256Digest(self): """ Check if this component is an ImplicitSha256Digest component. :return: True if this is an ImplicitSha256Digest component. :rtype: bool """ return self._type == Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST def toNumber(self): """ Interpret this name component as a network-ordered number and return an integer. :return: The integer number. :rtype: int """ result = 0 for i in range(self._value.size()): result *= 256 result += self._value.buf()[i] return result def toNumberWithMarker(self, marker): """ Interpret this name component as a network-ordered number with a marker and return an integer. :param int marker: The required first byte of the component. :return: The integer number. :rtype: int :raises RuntimeError: If the first byte of the component does not equal the marker. """ if self._value.size() <= 0 or self._value.buf()[0] != marker: raise RuntimeError( "Name component does not begin with the expected marker") result = 0 for i in range(1, self._value.size()): result *= 256 result += self._value.buf()[i] return result def toSegment(self): """ Interpret this name component as a segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer segment number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0x00) def toSegmentOffset(self): """ Interpret this name component as a segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer segment byte offset. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFB) def toVersion(self): """ Interpret this name component as a version number according to NDN naming conventions for "Versioning" (marker 0xFD). Note that this returns the exact number from the component without converting it to a time representation. http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer version number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFD) def toTimestamp(self): """ Interpret this name component as a timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The number of microseconds since the UNIX epoch (Thursday, 1 January 1970) not counting leap seconds. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFC) def toSequenceNumber(self): """ Interpret this name component as a sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer sequence number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFE) def equals(self, other): """ Check if this is the same component as other. :param Name.Component other: The other Component to compare with. :return: True if the components are equal, otherwise False. :rtype: bool """ return self._value.equals(other._value) and self._type == other._type def compare(self, other): """ Compare this to the other Component using NDN canonical ordering. :param Name.Component other: The other Component to compare with. :return: 0 If they compare equal, -1 if self comes before other in the canonical ordering, or 1 if self comes after other in the canonical ordering. :rtype: int :see: http://named-data.net/doc/0.2/technical/CanonicalOrder.html """ if self._type < other._type: return -1 if self._type > other._type: return 1 if self._value.size() < other._value.size(): return -1 if self._value.size() > other._value.size(): return 1 # The components are equal length. Just do a byte compare. return self._value.compare(other._value) @staticmethod def fromNumber(number): """ Create a component whose value is the nonNegativeInteger encoding of the number. :param int number: The number to be encoded. :return: The component value. :rtype: Name.Component """ encoder = TlvEncoder(8) encoder.writeNonNegativeInteger(number) return Name.Component(Blob(encoder.getOutput(), False)) @staticmethod def fromNumberWithMarker(number, marker): """ Create a component whose value is the marker appended with the nonNegativeInteger encoding of the number. :param int number: The number to be encoded. :param int marker: The marker to use as the first byte of the component. :return: The component value. :rtype: Name.Component """ encoder = TlvEncoder(9) # Encode backwards. encoder.writeNonNegativeInteger(number) encoder.writeNonNegativeInteger(marker) return Name.Component(Blob(encoder.getOutput(), False)) @staticmethod def fromSegment(segment): """ Create a component with the encoded segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int segment: The segment number. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(segment, 0x00) @staticmethod def fromSegmentOffset(segmentOffset): """ Create a component with the encoded segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int segmentOffset: The segment byte offset. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(segmentOffset, 0xFB) @staticmethod def fromVersion(version): """ Create a component with the encoded version number according to NDN naming conventions for "Versioning" (marker 0xFD). http://named-data.net/doc/tech-memos/naming-conventions.pdf Note that this encodes the exact value of version without converting from a time representation. :param int version: The version number. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(version, 0xFD) @staticmethod def fromTimestamp(timestamp): """ Create a component with the encoded timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int timestamp: The number of microseconds since the UNIX epoch (Thursday, 1 January 1970) not counting leap seconds. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(timestamp, 0xFC) @staticmethod def fromSequenceNumber(sequenceNumber): """ Create a component with the encoded sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :param int sequenceNumber: The sequence number. :return: The new Component. :rtype: Name.Component """ return Name.Component.fromNumberWithMarker(sequenceNumber, 0xFE) @staticmethod def fromImplicitSha256Digest(digest): """ Create a component of type ImplicitSha256DigestComponent, so that isImplicitSha256Digest() is true. :param digest: The SHA-256 digest value. :type digest: Blob or value for Blob constructor :return: The new Component. :rtype: Name.Component :raises RuntimeError: If the digest length is not 32 bytes. """ digestBlob = digest if isinstance(digest, Blob) else Blob(digest) if digestBlob.size() != 32: raise RuntimeError( "Name.Component.fromImplicitSha256Digest: The digest length must be 32 bytes") result = Name.Component(digestBlob) result._type = Name.Component.ComponentType.IMPLICIT_SHA256_DIGEST return result def getSuccessor(self): """ Get the successor of this component, as described in Name.getSuccessor. :return: A new Name.Component which is the successor of this. :rtype: Name.Component """ # Allocate an extra byte in case the result is larger. result = bytearray(self._value.size() + 1) carry = True for i in range(self._value.size() - 1, -1, -1): if carry: result[i] = (self._value.buf()[i] + 1) & 0xff carry = (result[i] == 0) else: result[i] = self._value.buf()[i] if carry: # Assume all the bytes were set to zero (or the component was # empty). In NDN ordering, carry does not mean to prepend a 1, # but to make a component one byte longer of all zeros. result[len(result) - 1] = 0 else: # We didn't need the extra byte. result = result[0:self._value.size()] return Name.Component(Blob(result, False)) # Python operators def __eq__(self, other): return type(other) is Name.Component and self.equals(other) def __ne__(self, other): return not self == other def __le__(self, other): return self.compare(other) <= 0 def __lt__(self, other): return self.compare(other) < 0 def __ge__(self, other): return self.compare(other) >= 0 def __gt__(self, other): return self.compare(other) > 0 def __len__(self): return self._value.size() def __str__(self): return self.toEscapedString() def __hash__(self): return hash(self._value)
class PublicKey(object): """ Create a new PublicKey by decoding the keyDer. Set the key type from the decoding. :param Blob keyDer: The blob of the PublicKeyInfo in terms of DER. :raises: UnrecognizedKeyFormatException if can't decode the key DER. """ def __init__(self, keyDer = None): # TODO: Implementation of managed properties? if keyDer == None: self._keyDer = Blob() self._keyType = None return self._keyDer = keyDer # Get the public key OID. oidString = "" try: parsedNode = DerNode.parse(keyDer.buf(), 0) rootChildren = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence( rootChildren, 0).getChildren() oidString = algorithmIdChildren[0].toVal() except DerDecodingException as ex: raise UnrecognizedKeyFormatException( "PublicKey.decodeKeyType: Error decoding the public key" + str(ex)) # Verify that the we can decode. if oidString == self.RSA_ENCRYPTION_OID: self._keyType = KeyType.RSA RSA.importKey(keyDer.toRawStr()) elif oidString == self.EC_ENCRYPTION_OID: self._keyType = KeyType.ECDSA # TODO: Check EC decoding. else: raise UnrecognizedKeyFormatException( "PublicKey.decodeKeyType: Unrecognized OID " + oidString) def toDer(self): """ Encode the public key into DER. :return: The encoded DER syntax tree. :rtype: DerNode """ return DerNode.parse(self._keyDer) def getDigest(self, digestAlgorithm = DigestAlgorithm.SHA256): """ Get the digest of the public key. :param digestAlgorithm: (optional) The digest algorithm. If omitted, use DigestAlgorithm.SHA256 . :type digestAlgorithm: int from DigestAlgorithm :return: The digest value :rtype: Blob """ if digestAlgorithm == DigestAlgorithm.SHA256: hashFunc = SHA256.new() hashFunc.update(self._keyDer.buf()) return Blob(hashFunc.digest()) else: raise RuntimeError("Unimplemented digest algorithm") def getKeyType(self): """ Get the key type. :return: The key type :rtype: an int from KeyType """ return self._keyType def getKeyDer(self): """ Get the raw bytes of the public key in DER format. :return: The public key DER :rtype: Blob """ return self._keyDer RSA_ENCRYPTION_OID = "1.2.840.113549.1.1.1" EC_ENCRYPTION_OID = "1.2.840.10045.2.1"
class SafeBag(object): """ There are three forms of the SafeBag constructor: SafeBag(certificate, privateKeyBag) - Create a SafeBag with the given certificate and private key. SafeBag(keyName, privateKeyBag, publicKeyEncoding [, password, digestAlgorithm, wireFormat]) - Create a SafeBag with given private key and a new self-signed certificate for the given public key. SafeBag(input) - Create a SafeBag by decoding the input as an NDN-TLV SafeBag. :param Data certificate: The certificate data packet (used only for SafeBag(certificate, privateKeyBag)). This copies the object. :param Blob privateKeyBag: The encoded private key. If encrypted, this is a PKCS #8 EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted PKCS #8 PrivateKeyInfo. :param password: (optional) The password for decrypting the private key in order to sign the self-signed certificate, which should have characters in the range of 1 to 127. If the password is supplied, use it to decrypt the PKCS #8 EncryptedPrivateKeyInfo. If the password is omitted or None, privateKeyBag is an unencrypted PKCS #8 PrivateKeyInfo. :type password: an array which implements the buffer protocol :param int digestAlgorithm: (optional) The digest algorithm for signing the self-signed certificate. If omitted, use DigestAlgorithm.SHA256 . :type digestAlgorithm: int from the DigestAlgorithm enum :param WireFormat wireFormat: (optional) A WireFormat object used to encode the self-signed certificate in order to sign it. If omitted, use WireFormat.getDefaultWireFormat(). :param input: The array with the bytes to decode. :type input: A Blob or an array type with int elements """ def __init__(self, arg1, privateKeyBag = None, publicKeyEncoding = None, password = None, digestAlgorithm = DigestAlgorithm.SHA256, wireFormat = None): if isinstance(arg1, Name): keyName = arg1 if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() self._certificate = SafeBag._makeSelfSignedCertificate( keyName, privateKeyBag, publicKeyEncoding, password, digestAlgorithm, wireFormat) self._privateKeyBag = privateKeyBag elif isinstance(arg1, Data): # The certificate is supplied. self._certificate = Data(arg1) self._privateKeyBag = privateKeyBag else: # Assume the first argument is the encoded SafeBag. self.wireDecode(arg1) def getCertificate(self): """ Get the certificate data packet. :return: The certificate as a Data packet. If you need to process it as a certificate object then you must create a new CertificateV2(data). :rtype: Data """ return self._certificate def getPrivateKeyBag(self): """ Get the encoded private key. :return: The encoded private key. If encrypted, this is a PKCS #8 EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted PKCS #8 PrivateKeyInfo. :rtype: Blob """ return self._privateKeyBag def wireDecode(self, input): """ Decode the input as an NDN-TLV SafeBag and update this object. :param input: The array with the bytes to decode. :type input: A Blob or an array type with int elements """ if isinstance(input, Blob): input = input.buf() # Decode directly as TLV. We don't support the WireFormat abstraction # because this isn't meant to go directly on the wire. decoder = TlvDecoder(input) endOffset = decoder.readNestedTlvsStart(Tlv.SafeBag_SafeBag) # Get the bytes of the certificate and decode. certificateBeginOffset = decoder.getOffset() certificateEndOffset = decoder.readNestedTlvsStart(Tlv.Data) decoder.seek(certificateEndOffset) self._certificate = Data() self._certificate.wireDecode( decoder.getSlice(certificateBeginOffset, certificateEndOffset), TlvWireFormat.get()) self._privateKeyBag = Blob( decoder.readBlobTlv(Tlv.SafeBag_EncryptedKeyBag), True) decoder.finishNestedTlvs(endOffset) def wireEncode(self, wireFormat = None): """ Encode this as an NDN-TLV SafeBag. :return: The encoded byte array as a Blob. :rtype: Blob """ # Encode directly as TLV. We don't support the WireFormat abstraction # because this isn't meant to go directly on the wire. encoder = TlvEncoder(256) saveLength = len(encoder) # Encode backwards. encoder.writeBlobTlv( Tlv.SafeBag_EncryptedKeyBag, self._privateKeyBag.buf()) # Add the entire Data packet encoding as is. encoder.writeBuffer( self._certificate.wireEncode(TlvWireFormat.get()).buf()) encoder.writeTypeAndLength( Tlv.SafeBag_SafeBag, len(encoder) - saveLength) return Blob(encoder.getOutput(), False) @staticmethod def _makeSelfSignedCertificate( keyName, privateKeyBag, publicKeyEncoding, password, digestAlgorithm, wireFormat): certificate = CertificateV2() # Set the name. now = Common.getNowMilliseconds() certificateName = Name(keyName) certificateName.append("self").appendVersion(int(now)) certificate.setName(certificateName) # Set the MetaInfo. certificate.getMetaInfo().setType(ContentType.KEY) # Set a one-hour freshness period. certificate.getMetaInfo().setFreshnessPeriod(3600 * 1000.0) # Set the content. publicKey = PublicKey(publicKeyEncoding) certificate.setContent(publicKey.getKeyDer()) # Create a temporary in-memory Tpm and import the private key. tpm = Tpm("", "", TpmBackEndMemory()) tpm._importPrivateKey(keyName, privateKeyBag.toBytes(), password) # Set the signature info. if publicKey.getKeyType() == KeyType.RSA: certificate.setSignature(Sha256WithRsaSignature()) elif publicKey.getKeyType() == KeyType.EC: certificate.setSignature(Sha256WithEcdsaSignature()) else: raise ValueError("Unsupported key type") signatureInfo = certificate.getSignature() KeyLocator.getFromSignature(signatureInfo).setType(KeyLocatorType.KEYNAME) KeyLocator.getFromSignature(signatureInfo).setKeyName(keyName) # Set a 20-year validity period. ValidityPeriod.getFromSignature(signatureInfo).setPeriod( now, now + 20 * 365 * 24 * 3600 * 1000.0) # Encode once to get the signed portion. encoding = certificate.wireEncode(wireFormat) signatureBytes = tpm.sign(encoding.toSignedBytes(), keyName, digestAlgorithm) signatureInfo.setSignature(signatureBytes) # Encode again to include the signature. certificate.wireEncode(wireFormat) return certificate
class SafeBag(object): """ There are three forms of the SafeBag constructor: SafeBag(certificate, privateKeyBag) - Create a SafeBag with the given certificate and private key. SafeBag(keyName, privateKeyBag, publicKeyEncoding [, password, digestAlgorithm, wireFormat]) - Create a SafeBag with given private key and a new self-signed certificate for the given public key. SafeBag(input) - Create a SafeBag by decoding the input as an NDN-TLV SafeBag. :param Data certificate: The certificate data packet (used only for SafeBag(certificate, privateKeyBag)). This copies the object. :param Blob privateKeyBag: The encoded private key. If encrypted, this is a PKCS #8 EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted PKCS #8 PrivateKeyInfo. :param password: (optional) The password for decrypting the private key in order to sign the self-signed certificate, which should have characters in the range of 1 to 127. If the password is supplied, use it to decrypt the PKCS #8 EncryptedPrivateKeyInfo. If the password is omitted or None, privateKeyBag is an unencrypted PKCS #8 PrivateKeyInfo. :type password: an array which implements the buffer protocol :param int digestAlgorithm: (optional) The digest algorithm for signing the self-signed certificate. If omitted, use DigestAlgorithm.SHA256 . :type digestAlgorithm: int from the DigestAlgorithm enum :param WireFormat wireFormat: (optional) A WireFormat object used to encode the self-signed certificate in order to sign it. If omitted, use WireFormat.getDefaultWireFormat(). :param input: The array with the bytes to decode. :type input: A Blob or an array type with int elements """ def __init__(self, arg1, privateKeyBag=None, publicKeyEncoding=None, password=None, digestAlgorithm=DigestAlgorithm.SHA256, wireFormat=None): if isinstance(arg1, Name): keyName = arg1 if wireFormat == None: # Don't use a default argument since getDefaultWireFormat can change. wireFormat = WireFormat.getDefaultWireFormat() self._certificate = SafeBag._makeSelfSignedCertificate( keyName, privateKeyBag, publicKeyEncoding, password, digestAlgorithm, wireFormat) self._privateKeyBag = privateKeyBag elif isinstance(arg1, Data): # The certificate is supplied. self._certificate = Data(arg1) self._privateKeyBag = privateKeyBag else: # Assume the first argument is the encoded SafeBag. self.wireDecode(arg1) def getCertificate(self): """ Get the certificate data packet. :return: The certificate as a Data packet. If you need to process it as a certificate object then you must create a new CertificateV2(data). :rtype: Data """ return self._certificate def getPrivateKeyBag(self): """ Get the encoded private key. :return: The encoded private key. If encrypted, this is a PKCS #8 EncryptedPrivateKeyInfo. If not encrypted, this is an unencrypted PKCS #8 PrivateKeyInfo. :rtype: Blob """ return self._privateKeyBag def wireDecode(self, input): """ Decode the input as an NDN-TLV SafeBag and update this object. :param input: The array with the bytes to decode. :type input: A Blob or an array type with int elements """ if isinstance(input, Blob): input = input.buf() # Decode directly as TLV. We don't support the WireFormat abstraction # because this isn't meant to go directly on the wire. decoder = TlvDecoder(input) endOffset = decoder.readNestedTlvsStart(Tlv.SafeBag_SafeBag) # Get the bytes of the certificate and decode. certificateBeginOffset = decoder.getOffset() certificateEndOffset = decoder.readNestedTlvsStart(Tlv.Data) decoder.seek(certificateEndOffset) self._certificate = Data() self._certificate.wireDecode( decoder.getSlice(certificateBeginOffset, certificateEndOffset), TlvWireFormat.get()) self._privateKeyBag = Blob( decoder.readBlobTlv(Tlv.SafeBag_EncryptedKeyBag), True) decoder.finishNestedTlvs(endOffset) def wireEncode(self, wireFormat=None): """ Encode this as an NDN-TLV SafeBag. :return: The encoded byte array as a Blob. :rtype: Blob """ # Encode directly as TLV. We don't support the WireFormat abstraction # because this isn't meant to go directly on the wire. encoder = TlvEncoder(256) saveLength = len(encoder) # Encode backwards. encoder.writeBlobTlv(Tlv.SafeBag_EncryptedKeyBag, self._privateKeyBag.buf()) # Add the entire Data packet encoding as is. encoder.writeBuffer( self._certificate.wireEncode(TlvWireFormat.get()).buf()) encoder.writeTypeAndLength(Tlv.SafeBag_SafeBag, len(encoder) - saveLength) return Blob(encoder.getOutput(), False) @staticmethod def _makeSelfSignedCertificate(keyName, privateKeyBag, publicKeyEncoding, password, digestAlgorithm, wireFormat): certificate = CertificateV2() # Set the name. now = Common.getNowMilliseconds() certificateName = Name(keyName) certificateName.append("self").appendVersion(int(now)) certificate.setName(certificateName) # Set the MetaInfo. certificate.getMetaInfo().setType(ContentType.KEY) # Set a one-hour freshness period. certificate.getMetaInfo().setFreshnessPeriod(3600 * 1000.0) # Set the content. publicKey = PublicKey(publicKeyEncoding) certificate.setContent(publicKey.getKeyDer()) # Create a temporary in-memory Tpm and import the private key. tpm = Tpm("", "", TpmBackEndMemory()) tpm._importPrivateKey(keyName, privateKeyBag.toBytes(), password) # Set the signature info. if publicKey.getKeyType() == KeyType.RSA: certificate.setSignature(Sha256WithRsaSignature()) elif publicKey.getKeyType() == KeyType.EC: certificate.setSignature(Sha256WithEcdsaSignature()) else: raise ValueError("Unsupported key type") signatureInfo = certificate.getSignature() KeyLocator.getFromSignature(signatureInfo).setType( KeyLocatorType.KEYNAME) KeyLocator.getFromSignature(signatureInfo).setKeyName(keyName) # Set a 20-year validity period. ValidityPeriod.getFromSignature(signatureInfo).setPeriod( now, now + 20 * 365 * 24 * 3600 * 1000.0) # Encode once to get the signed portion. encoding = certificate.wireEncode(wireFormat) signatureBytes = tpm.sign(encoding.toSignedBytes(), keyName, digestAlgorithm) signatureInfo.setSignature(signatureBytes) # Encode again to include the signature. certificate.wireEncode(wireFormat) return certificate
class Component(object): """ Create a new Name.Component. :param value: (optional) If value is already a Blob or Name.Component, then take another pointer to the value. Otherwise, create a new Blob with a copy of the value. If omitted, create an empty component. :type value: Blob or Name.Component or value for Blob constructor """ def __init__(self, value = None): if type(value) is Name.Component: # Use the existing Blob in the other Component. self._value = value._value elif value == None: self._value = Blob([]) else: # Blob will make a copy. self._value = value if isinstance(value, Blob) else Blob(value) def getValue(self): """ Get the value of the component. :return: The component value. :rtype: Blob """ return self._value def toEscapedString(self, result = None): """ Convert this component to a string, escaping characters according to the NDN URI Scheme. This also adds "..." to a value with zero or more ".". :param BytesIO result: (optional) The BytesIO stream to write to. If omitted, return a str with the result. :return: The result as a string (only if result is omitted). :rtype: str """ if result == None: return Name.toEscapedString(self._value.buf()) else: Name.toEscapedString(self._value.buf(), result) def toNumber(self): """ Interpret this name component as a network-ordered number and return an integer. :return: The integer number. :rtype: int """ result = 0 for i in range(self._value.size()): result *= 256 result += self._value.buf()[i] return result def toNumberWithMarker(self, marker): """ Interpret this name component as a network-ordered number with a marker and return an integer. :param int marker: The required first byte of the component. :return: The integer number. :rtype: int :raises RuntimeError: If the first byte of the component does not equal the marker. """ if self._value.size() <= 0 or self._value.buf()[0] != marker: raise RuntimeError( "Name component does not begin with the expected marker") result = 0 for i in range(1, self._value.size()): result *= 256 result += self._value.buf()[i] return result def toSegment(self): """ Interpret this name component as a segment number according to NDN naming conventions for "Segment number" (marker 0x00). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer segment number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0x00) def toSegmentOffset(self): """ Interpret this name component as a segment byte offset according to NDN naming conventions for segment "Byte offset" (marker 0xFB). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer segment byte offset. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFB) def toVersion(self): """ Interpret this name component as a version number according to NDN naming conventions for "Versioning" (marker 0xFD). Note that this returns the exact number from the component without converting it to a time representation. http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer version number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFD) def toTimestamp(self): """ Interpret this name component as a timestamp according to NDN naming conventions for "Timestamp" (marker 0xFC). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The number of microseconds since the UNIX epoch (Thursday, 1 January 1970) not counting leap seconds. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFC) def toSequenceNumber(self): """ Interpret this name component as a sequence number according to NDN naming conventions for "Sequencing" (marker 0xFE). http://named-data.net/doc/tech-memos/naming-conventions.pdf :return: The integer sequence number. :rtype: int :raises RuntimeError: If the first byte of the component is not the expected marker. """ return self.toNumberWithMarker(0xFE) def equals(self, other): """ Check if this is the same component as other. :param Name.Component other: The other Component to compare with. :return: True if the components are equal, otherwise False. :rtype: bool """ return self._value.equals(other._value) def compare(self, other): """ Compare this to the other Component using NDN canonical ordering. :param Name.Component other: The other Component to compare with. :return: 0 If they compare equal, -1 if self comes before other in the canonical ordering, or 1 if self comes after other in the canonical ordering. :rtype: int :see: http://named-data.net/doc/0.2/technical/CanonicalOrder.html """ if self._value.size() < other._value.size(): return -1 if self._value.size() > other._value.size(): return 1 # The components are equal length. Just do a byte compare. return self._value.compare(other._value) @staticmethod def fromNumber(number): """ Create a component whose value is the nonNegativeInteger encoding of the number. :param int number: The number to be encoded. :return: The component value. :rtype: Name.Component """ encoder = TlvEncoder(8) encoder.writeNonNegativeInteger(number) return Name.Component(Blob(encoder.getOutput(), False)) @staticmethod def fromNumberWithMarker(number, marker): """ Create a component whose value is the marker appended with the nonNegativeInteger encoding of the number. :param int number: The number to be encoded. :param int marker: The marker to use as the first byte of the component. :return: The component value. :rtype: Name.Component """ encoder = TlvEncoder(9) # Encode backwards. encoder.writeNonNegativeInteger(number) encoder.writeNonNegativeInteger(marker) return Name.Component(Blob(encoder.getOutput(), False)) # Python operators def __eq__(self, other): return type(other) is Name.Component and self.equals(other) def __ne__(self, other): return not self == other def __le__(self, other): return self.compare(other) <= 0 def __lt__(self, other): return self.compare(other) < 0 def __ge__(self, other): return self.compare(other) >= 0 def __gt__(self, other): return self.compare(other) > 0 def __len__(self): return self._value.size() def __str__(self): return self.toEscapedString()