def getSchedule(self, name):
        """
        Get a schedule with the given name.

        :param str name: The name of the schedule.
        :return: A new Schedule object.
        :rtype: Schedule
        :raises GroupManagerDb.Error: If the schedule does not exist or other
          database error.
        """
        schedule = None

        try:
            cursor = self._database.cursor()
            cursor.execute("SELECT schedule FROM schedules WHERE schedule_name=?", (name,))
            result = cursor.fetchone()
            if result != None:
                schedule = Schedule()
                schedule.wireDecode(bytearray(result[0]))
            cursor.close()
        except Exception as ex:
            raise GroupManagerDb.Error("Sqlite3GroupManagerDb.getSchedule: SQLite error: " + str(ex))

        if schedule == None:
            raise GroupManagerDb.Error("Sqlite3GroupManagerDb.getSchedule: Cannot get the result from the database")

        return schedule
    def getSchedule(self, name):
        """
        Get a schedule with the given name.

        :param str name: The name of the schedule.
        :return: A new Schedule object.
        :rtype: Schedule
        :raises GroupManagerDb.Error: If the schedule does not exist or other
          database error.
        """
        schedule = None

        try:
            cursor = self._database.cursor()
            cursor.execute(
              "SELECT schedule FROM schedules WHERE schedule_name=?", (name, ))
            result = cursor.fetchone()
            if result != None:
                schedule = Schedule()
                schedule.wireDecode(bytearray(result[0]))
            cursor.close()
        except Exception as ex:
            raise GroupManagerDb.Error(
              "Sqlite3GroupManagerDb.getSchedule: SQLite error: " + str(ex))

        if schedule == None:
            raise GroupManagerDb.Error(
              "Sqlite3GroupManagerDb.getSchedule: Cannot get the result from the database")

        return schedule
Exemple #3
0
    def _handleCoveringKey(self, interest, data, timeSlot, onEncryptedKeys,
                           onError):
        """
        This is called from an expressInterest OnData to check that the
        encryption key contained in data fits the timeSlot. This sends a refined
        interest if required.

        :param Interest interest: The interest given to expressInterest.
        :param Data data: The fetched Data packet.
        :param float timeSlot: The time slot as milliseconds since Jan 1, 1970 UTC.
        :param onEncryptedKeys: When there are no more interests to process,
          this calls onEncryptedKeys(keys) where keys is a list of encrypted
          content key Data packets. If onEncryptedKeys is None, this does not
          use it.
        :type onEncryptedKeys: function object
        :param onError: This calls onError(errorCode, message) for an error.
        :type onError: function object
        """
        timeCount = round(timeSlot)
        keyRequest = self._keyRequests[timeCount]

        interestName = interest.getName()
        keyName = data.getName()

        begin = Schedule.fromIsoString(
            str(keyName.get(Producer.START_TIME_STAMP_INDEX).getValue()))
        end = Schedule.fromIsoString(
            str(keyName.get(Producer.END_TIME_STAMP_INDEX).getValue()))

        if timeSlot >= end:
            # If the received E-KEY covers some earlier period, try to retrieve
            # an E-KEY covering a later one.
            timeRange = Exclude(interest.getExclude())
            Producer.excludeBefore(
                timeRange, keyName.get(Producer.START_TIME_STAMP_INDEX))
            keyRequest.repeatAttempts[interestName] = 0
            self._sendKeyInterest(
                Interest(interestName).setExclude(timeRange).setChildSelector(
                    1), timeSlot, onEncryptedKeys, onError)
        else:
            # If the received E-KEY covers the content key, encrypt the content.
            encryptionKey = data.getContent()
            # If everything is correct, save the E-KEY as the current key.
            if self._encryptContentKey(encryptionKey, keyName, timeSlot,
                                       onEncryptedKeys, onError):
                keyInfo = self._eKeyInfo[interestName]
                keyInfo.beginTimeSlot = begin
                keyInfo.endTimeSlot = end
                keyInfo.keyBits = encryptionKey
Exemple #4
0
    def getGroupKey(self, timeSlot):
        """
        Create a group key for the interval into which timeSlot falls. This
        creates a group key if it doesn't exist, and encrypts the key using the
        public key of each eligible member.

        :param float timeSlot: The time slot to cover as milliseconds since
          Jan 1, 1970 UTC.
        :return: A List of Data packets where the first is the E-KEY data packet
          with the group's public key and the rest are the D-KEY data packets
          with the group's private key encrypted with the public key of each
          eligible member.
        :raises GroupManagerDb.Error: For a database error.
        :raises SecurityException: For an error using the security KeyChain.
        """
        unsortedMemberKeys = {}
        result = []

        # Get the time interval.
        finalInterval = self._calculateInterval(timeSlot, unsortedMemberKeys)
        if finalInterval.isValid() == False:
            return result

        startTimeStamp = Schedule.toIsoString(finalInterval.getStartTime())
        endTimeStamp = Schedule.toIsoString(finalInterval.getEndTime())

        # Generate the private and public keys.
        (privateKeyBlob, publicKeyBlob) = self._generateKeyPair()

        # Add the first element to the result.
        # The E-KEY (public key) data packet name convention is:
        # /<data_type>/E-KEY/[start-ts]/[end-ts]
        data = self._createEKeyData(startTimeStamp, endTimeStamp,
                                    publicKeyBlob)
        result.append(data)

        # Encrypt the private key with the public key from each member's certificate.
        # Sort the key names.
        for keyName in sorted(unsortedMemberKeys.keys()):
            certificateKey = unsortedMemberKeys[keyName]

            # Generate the name of the packet.
            # The D-KEY (private key) data packet name convention is:
            # /<data_type>/D-KEY/[start-ts]/[end-ts]/[member-name]
            data = self._createDKeyData(startTimeStamp, endTimeStamp, keyName,
                                        privateKeyBlob, certificateKey)
            result.append(data)

        return result
Exemple #5
0
    def _handleCoveringKey(
          self, interest, data, timeSlot, onEncryptedKeys, onError):
        """
        This is called from an expressInterest OnData to check that the
        encryption key contained in data fits the timeSlot. This sends a refined
        interest if required.

        :param Interest interest: The interest given to expressInterest.
        :param Data data: The fetched Data packet.
        :param float timeSlot: The time slot as milliseconds since Jan 1, 1970 UTC.
        :param onEncryptedKeys: When there are no more interests to process,
          this calls onEncryptedKeys(keys) where keys is a list of encrypted
          content key Data packets. If onEncryptedKeys is None, this does not
          use it.
        :type onEncryptedKeys: function object
        :param onError: This calls onError(errorCode, message) for an error.
        :type onError: function object
        """
        timeCount = round(timeSlot)
        keyRequest = self._keyRequests[timeCount]

        interestName = interest.getName()
        keyName = data.getName()

        begin = Schedule.fromIsoString(
          str(keyName.get(Producer.START_TIME_STAMP_INDEX).getValue()))
        end = Schedule.fromIsoString(
          str(keyName.get(Producer.END_TIME_STAMP_INDEX).getValue()))

        if timeSlot >= end:
            # If the received E-KEY covers some earlier period, try to retrieve
            # an E-KEY covering a later one.
            timeRange = Exclude(interest.getExclude())
            Producer.excludeBefore(timeRange, keyName.get(Producer.START_TIME_STAMP_INDEX))
            keyRequest.repeatAttempts[interestName] = 0
            self._sendKeyInterest(
              Interest(interestName).setExclude(timeRange).setChildSelector(1),
              timeSlot, onEncryptedKeys, onError)
        else:
            # If the received E-KEY covers the content key, encrypt the content.
            encryptionKey = data.getContent()
            # If everything is correct, save the E-KEY as the current key.
            if self._encryptContentKey(
              encryptionKey, keyName, timeSlot, onEncryptedKeys, onError):
                keyInfo = self._eKeyInfo[interestName]
                keyInfo.beginTimeSlot = begin
                keyInfo.endTimeSlot = end
                keyInfo.keyBits = encryptionKey
Exemple #6
0
    def getGroupKey(self, timeSlot):
        """
        Create a group key for the interval into which timeSlot falls. This
        creates a group key if it doesn't exist, and encrypts the key using the
        public key of each eligible member.

        :param float timeSlot: The time slot to cover as milliseconds since
          Jan 1, 1970 UTC.
        :return: A List of Data packets where the first is the E-KEY data packet
          with the group's public key and the rest are the D-KEY data packets
          with the group's private key encrypted with the public key of each
          eligible member.
        :raises GroupManagerDb.Error: For a database error.
        :raises SecurityException: For an error using the security KeyChain.
        """
        unsortedMemberKeys = {}
        result = []

        # Get the time interval.
        finalInterval = self._calculateInterval(timeSlot, unsortedMemberKeys)
        if finalInterval.isValid() == False:
          return result

        startTimeStamp = Schedule.toIsoString(finalInterval.getStartTime())
        endTimeStamp = Schedule.toIsoString(finalInterval.getEndTime())

        # Generate the private and public keys.
        (privateKeyBlob, publicKeyBlob) = self._generateKeyPair()

        # Add the first element to the result.
        # The E-KEY (public key) data packet name convention is:
        # /<data_type>/E-KEY/[start-ts]/[end-ts]
        data = self._createEKeyData(startTimeStamp, endTimeStamp, publicKeyBlob)
        result.append(data)

        # Encrypt the private key with the public key from each member's certificate.
        # Sort the key names.
        for keyName in sorted(unsortedMemberKeys.keys()):
          certificateKey = unsortedMemberKeys[keyName]

          # Generate the name of the packet.
          # The D-KEY (private key) data packet name convention is:
          # /<data_type>/D-KEY/[start-ts]/[end-ts]/[member-name]
          data = self._createDKeyData(
            startTimeStamp, endTimeStamp, keyName, privateKeyBlob, certificateKey)
          result.append(data)

        return result
Exemple #7
0
    def produce(self, data, timeSlot, content, onError=defaultOnError):
        """
        Encrypt the given content with the content key that covers timeSlot, and
        update the data packet with the encrypted content and an appropriate
        data name.

        :param Data data: An empty Data object which is updated.
        :param float timeSlot: The time slot as milliseconds since Jan 1, 1970 UTC.
        :param Blob content: The content to encrypt.
        :param onError: (optional) This calls onError(errorCode, message) for an
          error, where errorCode is from EncryptError.ErrorCode and message is a
          str. If omitted, use a default callback which does nothing.
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onError: function object
        """
        # Get a content key.
        contentKeyName = self.createContentKey(timeSlot, None, onError)
        contentKey = self._database.getContentKey(timeSlot)

        # Produce data.
        dataName = Name(self._namespace)
        dataName.append(Schedule.toIsoString(timeSlot))

        data.setName(dataName)
        params = EncryptParams(EncryptAlgorithmType.AesCbc, 16)
        Encryptor.encryptData(data, content, contentKeyName, contentKey,
                              params)
        self._keyChain.sign(data)
Exemple #8
0
    def produce(self, data, timeSlot, content, onError=defaultOnError):
        """
        Encrypt the given content with the content key that covers timeSlot, and
        update the data packet with the encrypted content and an appropriate
        data name.

        :param Data data: An empty Data object which is updated.
        :param float timeSlot: The time slot as milliseconds since Jan 1, 1970 UTC.
        :param Blob content: The content to encrypt.
        :param onError: (optional) This calls onError(errorCode, message) for an
          error, where errorCode is from EncryptError.ErrorCode and message is a
          str. If omitted, use a default callback which does nothing.
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onError: function object
        """
        # Get a content key.
        contentKeyName = self.createContentKey(timeSlot, None, onError)
        contentKey = self._database.getContentKey(timeSlot)

        # Produce data.
        dataName = Name(self._namespace)
        dataName.append(Schedule.toIsoString(timeSlot))

        data.setName(dataName)
        params = EncryptParams(EncryptAlgorithmType.AesCbc, 16)
        Encryptor.encryptData(data, content, contentKeyName, contentKey, params)
        self._keyChain.sign(data)
Exemple #9
0
    def __str__(self):
        """
        Get a string representation of this certificate.

        :return: The string representation.
        :rtype: str
        """
        result = ""
        result += "Certificate name:\n"
        result += "  " + self.getName().toUri() + "\n"
        result += "Validity:\n"
        result += "  NotBefore: " + Schedule.toIsoString(
          self.getValidityPeriod().getNotBefore()) + "\n"
        result += "  NotAfter: " + Schedule.toIsoString(
          self.getValidityPeriod().getNotAfter()) + "\n"

        # TODO: Print the extension.

        result += "Public key bits:\n"
        try:
            result += Common.base64Encode(self.getPublicKey().toBytes(), True)
        except:
            # No public key.
            pass

        result += "Signature Information:\n"
        result += "  Signature Type: "
        if isinstance(self.getSignature(), Sha256WithEcdsaSignature):
            result += "SignatureSha256WithEcdsa\n"
        elif isinstance(self.getSignature(), Sha256WithRsaSignature):
            result += "SignatureSha256WithRsa\n"
        else:
            result += "<unknown>\n"

        if KeyLocator.canGetFromSignature(self.getSignature()):
            result += "  Key Locator: "
            keyLocator = KeyLocator.getFromSignature(self.getSignature())
            if keyLocator.getType() == KeyLocatorType.KEYNAME:
                if keyLocator.getKeyName().equals(self.getKeyName()):
                    result += "Self-Signed "

                result += "Name=" + keyLocator.getKeyName().toUri() + "\n"
            else:
                result += "<no KeyLocator key name>\n"

        return result
Exemple #10
0
    def __str__(self):
        """
        Get a string representation of this certificate.

        :return: The string representation.
        :rtype: str
        """
        result = ""
        result += "Certificate name:\n"
        result += "  " + self.getName().toUri() + "\n"
        result += "Validity:\n"
        result += "  NotBefore: " + Schedule.toIsoString(
            self.getValidityPeriod().getNotBefore()) + "\n"
        result += "  NotAfter: " + Schedule.toIsoString(
            self.getValidityPeriod().getNotAfter()) + "\n"

        # TODO: Print the extension.

        result += "Public key bits:\n"
        try:
            result += Common.base64Encode(self.getPublicKey().toBytes(), True)
        except:
            # No public key.
            pass

        result += "Signature Information:\n"
        result += "  Signature Type: "
        if type(self.getSignature()) is Sha256WithEcdsaSignature:
            result += "SignatureSha256WithEcdsa\n"
        elif type(self.getSignature()) is Sha256WithRsaSignature:
            result += "SignatureSha256WithRsa\n"
        else:
            result += "<unknown>\n"

        if KeyLocator.canGetFromSignature(self.getSignature()):
            result += "  Key Locator: "
            keyLocator = KeyLocator.getFromSignature(self.getSignature())
            if keyLocator.getType() == KeyLocatorType.KEYNAME:
                if keyLocator.getKeyName().equals(self.getKeyName()):
                    result += "Self-Signed "

                result += "Name=" + keyLocator.getKeyName().toUri() + "\n"
            else:
                result += "<no KeyLocator key name>\n"

        return result
Exemple #11
0
    def _encryptContentKey(self, encryptionKey, eKeyName, timeSlot,
                           onEncryptedKeys, onError):
        """
        Get the content key from the database_ and encrypt it for the timeSlot
          using encryptionKey.

        :param Blob encryptionKey: The encryption key value.
        :param Name eKeyName: The key name for the EncryptedContent.
        :param float timeSlot: The time slot as milliseconds since Jan 1, 1970 UTC.
        :param onEncryptedKeys: When there are no more interests to process,
           this calls onEncryptedKeys(keys) where keys is a list of encrypted
           content key Data packets. If onEncryptedKeys is None, this does not
           use it.
        :type onEncryptedKeys: function object
        :param onError: This calls onError(errorCode, message) for an error.
        :type onError: function object
        :return: True if encryption succeeds, otherwise False.
        :rtype: bool
        """
        timeCount = round(timeSlot)
        keyRequest = self._keyRequests[timeCount]

        keyName = Name(self._namespace)
        keyName.append(Encryptor.NAME_COMPONENT_C_KEY)
        keyName.append(
          Schedule.toIsoString(Producer._getRoundedTimeSlot(timeSlot)))

        contentKey = self._database.getContentKey(timeSlot)

        cKeyData = Data()
        cKeyData.setName(keyName)
        params = EncryptParams(EncryptAlgorithmType.RsaOaep)
        try:
            Encryptor.encryptData(
              cKeyData, contentKey, eKeyName, encryptionKey, params)
        except Exception as ex:
            try:
                onError(EncryptError.ErrorCode.EncryptionFailure,
                        "encryptData error: " + repr(ex))
            except:
                logging.exception("Error in onError")
            return False

        self._keyChain.sign(cKeyData)
        keyRequest.encryptedKeys.append(cKeyData)
        self._updateKeyRequest(keyRequest, timeCount, onEncryptedKeys)
        return True
Exemple #12
0
    def _encryptContentKey(self, encryptionKey, eKeyName, timeSlot,
                           onEncryptedKeys, onError):
        """
        Get the content key from the database_ and encrypt it for the timeSlot
          using encryptionKey.

        :param Blob encryptionKey: The encryption key value.
        :param Name eKeyName: The key name for the EncryptedContent.
        :param float timeSlot: The time slot as milliseconds since Jan 1, 1970 UTC.
        :param onEncryptedKeys: When there are no more interests to process,
           this calls onEncryptedKeys(keys) where keys is a list of encrypted
           content key Data packets. If onEncryptedKeys is None, this does not
           use it.
        :type onEncryptedKeys: function object
        :param onError: This calls onError(errorCode, message) for an error.
        :type onError: function object
        :return: True if encryption succeeds, otherwise False.
        :rtype: bool
        """
        timeCount = round(timeSlot)
        keyRequest = self._keyRequests[timeCount]

        keyName = Name(self._namespace)
        keyName.append(Encryptor.NAME_COMPONENT_C_KEY)
        keyName.append(
            Schedule.toIsoString(Producer._getRoundedTimeSlot(timeSlot)))

        contentKey = self._database.getContentKey(timeSlot)

        cKeyData = Data()
        cKeyData.setName(keyName)
        params = EncryptParams(EncryptAlgorithmType.RsaOaep)
        try:
            Encryptor.encryptData(cKeyData, contentKey, eKeyName,
                                  encryptionKey, params)
        except Exception as ex:
            try:
                onError(EncryptError.ErrorCode.EncryptionFailure,
                        "encryptData error: " + repr(ex))
            except:
                logging.exception("Error in onError")
            return False

        self._keyChain.sign(cKeyData)
        keyRequest.encryptedKeys.append(cKeyData)
        self._updateKeyRequest(keyRequest, timeCount, onEncryptedKeys)
        return True
    def insert(self, certificate):
        """
        Insert the certificate into the cache. The inserted certificate will be
        removed no later than its NotAfter time, or maxLifetimeMilliseconds
        given to the constructor.

        :param CertificateV2 certificate: The certificate object, which is
          copied.
        """
        notAfterTime = certificate.getValidityPeriod().getNotAfter()
        # _nowOffsetMilliseconds is only used for testing.
        now = Common.getNowMilliseconds() + self._nowOffsetMilliseconds
        if notAfterTime < now:
            logging.getLogger(__name__).info(
                "Not adding " + certificate.getName().toUri() +
                ": already expired at " + Schedule.toIsoString(notAfterTime))
            return

        removalTime = min(notAfterTime, now + self._maxLifetimeMilliseconds)
        if removalTime < self._nextRefreshTime:
            # We need to run refresh() sooner.
            self._nextRefreshTime = removalTime

        logging.getLogger(__name__).info("Adding " +
                                         certificate.getName().toUri() +
                                         ", will remove in " +
                                         str((removalTime - now) /
                                             (3600 * 1000.0)) + " hours")

        certificateCopy = CertificateV2(certificate)
        certificateName = certificateCopy.getName()

        if certificateName in self._certificatesByName:
            # A duplicate name. Simply replace.
            self._certificatesByName[
                certificateName]._certificate = certificateCopy
            self._certificatesByName[
                certificateName]._removalTime = removalTime
        else:
            # Insert into _certificatesByNameKeys sorted.
            # Keep it sync with _certificatesByName.
            self._certificatesByName[
                certificateName] = CertificateCacheV2._Entry(
                    certificateCopy, removalTime)
            bisect.insort(self._certificatesByNameKeys, certificateName)
    def insert(self, certificate):
        """
        Insert the certificate into the cache. The inserted certificate will be
        removed no later than its NotAfter time, or maxLifetimeMilliseconds
        given to the constructor.

        :param CertificateV2 certificate: The certificate object, which is
          copied.
        """
        notAfterTime = certificate.getValidityPeriod().getNotAfter()
        # _nowOffsetMilliseconds is only used for testing.
        now = Common.getNowMilliseconds() + self._nowOffsetMilliseconds
        if notAfterTime < now:
            logging.getLogger(__name__).info("Not adding " +
              certificate.getName().toUri() + ": already expired at " +
              Schedule.toIsoString(notAfterTime))
            return

        removalTime = min(notAfterTime, now + self._maxLifetimeMilliseconds)
        if removalTime < self._nextRefreshTime:
            # We need to run refresh() sooner.
            self._nextRefreshTime = removalTime

        logging.getLogger(__name__).info("Adding " + certificate.getName().toUri() +
          ", will remove in " + str((removalTime - now) / (3600 * 1000.0)) +
          " hours")

        certificateCopy = CertificateV2(certificate)
        certificateName = certificateCopy.getName()

        if certificateName in self._certificatesByName:
            # A duplicate name. Simply replace.
            self._certificatesByName[certificateName]._certificate = certificateCopy
            self._certificatesByName[certificateName]._removalTime = removalTime
        else:
            # Insert into _certificatesByNameKeys sorted.
            # Keep it sync with _certificatesByName.
            self._certificatesByName[certificateName] = CertificateCacheV2._Entry(
              certificateCopy, removalTime)
            bisect.insort(self._certificatesByNameKeys, certificateName)
Exemple #15
0
    def createContentKey(self,
                         timeSlot,
                         onEncryptedKeys,
                         onError=defaultOnError):
        """
        Create the content key corresponding to the timeSlot. This first checks
        if the content key exists. For an existing content key, this returns the
        content key name directly. If the key does not exist, this creates one
        and encrypts it using the corresponding E-KEYs. The encrypted content
        keys are passed to the onEncryptedKeys callback.

        :param float timeSlot: The time slot as milliseconds since Jan 1,
          1970 UTC.
        :param onEncryptedKeys: If this creates a content key, then this calls
          onEncryptedKeys(keys) where keys is a list of encrypted content key
          Data packets. If onEncryptedKeys is None, this does not use it.
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onEncryptedKeys: function object
        :param onError: (optional) This calls  errorCode, message) for an
          error, where errorCode is from EncryptError.ErrorCode and message is a
          str. If omitted, use a default callback which does nothing.
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onError: function object
        :return: The content key name.
        :rtype: Name
        """
        hourSlot = Producer._getRoundedTimeSlot(timeSlot)

        # Create the content key name.
        contentKeyName = Name(self._namespace)
        contentKeyName.append(Encryptor.NAME_COMPONENT_C_KEY)
        contentKeyName.append(Schedule.toIsoString(hourSlot))

        # Check if we have created the content key before.
        if self._database.hasContentKey(timeSlot):
            # We have created the content key. Return its name directly.
            return contentKeyName

        # We haven't created the content key. Create one and add it into the
        # database.
        aesParams = AesKeyParams(128)
        contentKeyBits = AesAlgorithm.generateKey(aesParams).getKeyBits()
        self._database.addContentKey(timeSlot, contentKeyBits)

        # Now we need to retrieve the E-KEYs for content key encryption.
        timeCount = round(timeSlot)
        self._keyRequests[timeCount] = Producer._KeyRequest(len(
            self._eKeyInfo))
        keyRequest = self._keyRequests[timeCount]

        # Send interests for all nodes in the tree.
        for keyName in self._eKeyInfo:
            # For each current E-KEY.
            keyInfo = self._eKeyInfo[keyName]
            if (timeSlot < keyInfo.beginTimeSlot
                    or timeSlot >= keyInfo.endTimeSlot):
                # The current E-KEY cannot cover the content key, so retrieve one.
                keyRequest.repeatAttempts[keyName] = 0
                self._sendKeyInterest(Interest(keyName), timeSlot,
                                      onEncryptedKeys, onError)
            else:
                # The current E-KEY can cover the content key.
                # Encrypt the content key directly.
                eKeyName = Name(keyName)
                eKeyName.append(Schedule.toIsoString(keyInfo.beginTimeSlot))
                eKeyName.append(Schedule.toIsoString(keyInfo.endTimeSlot))
                self._encryptContentKey(keyInfo.keyBits, eKeyName, timeSlot,
                                        onEncryptedKeys, onError)

        return contentKeyName
Exemple #16
0
    def getGroupKey(self, timeSlot, needRegenerate=True):
        """
        Create a group key for the interval into which timeSlot falls. This
        creates a group key if it doesn't exist, and encrypts the key using the
        public key of each eligible member.

        :param float timeSlot: The time slot to cover as milliseconds since
          Jan 1, 1970 UTC.
        :param bool needRegenerate: (optional) needRegenerate should be True if
          this is the first time this method is called, or a member was removed.
          needRegenerate can be False if this is not the first time this method
          is called, or a member was added. If omitted, use True.
        :return: A List of Data packets where the first is the E-KEY data packet
          with the group's public key and the rest are the D-KEY data packets
          with the group's private key encrypted with the public key of each
          eligible member.
        :raises GroupManagerDb.Error: For a database error.
        :raises SecurityException: For an error using the security KeyChain.
        """
        unsortedMemberKeys = {}
        result = []

        # Get the time interval.
        finalInterval = self._calculateInterval(timeSlot, unsortedMemberKeys)
        if finalInterval.isValid() == False:
            return result

        startTimeStamp = Schedule.toIsoString(finalInterval.getStartTime())
        endTimeStamp = Schedule.toIsoString(finalInterval.getEndTime())

        # Generate the private and public keys.
        eKeyName = Name(self._namespace)
        eKeyName.append(Encryptor.NAME_COMPONENT_E_KEY).append(
            startTimeStamp).append(endTimeStamp)

        if not needRegenerate and self._database.hasEKey(eKeyName):
            (publicKeyBlob, privateKeyBlob) = self._getEKey(eKeyName)
        else:
            (privateKeyBlob, publicKeyBlob) = self._generateKeyPair()
            if self._database.hasEKey(eKeyName):
                self._deleteEKey(eKeyName)
            self._addEKey(eKeyName, publicKeyBlob, privateKeyBlob)

        # Add the first element to the result.
        # The E-KEY (public key) data packet name convention is:
        # /<data_type>/E-KEY/[start-ts]/[end-ts]
        data = self._createEKeyData(startTimeStamp, endTimeStamp,
                                    publicKeyBlob)
        result.append(data)

        # Encrypt the private key with the public key from each member's certificate.
        # Sort the key names.
        for keyName in sorted(unsortedMemberKeys.keys()):
            certificateKey = unsortedMemberKeys[keyName]

            # Generate the name of the packet.
            # The D-KEY (private key) data packet name convention is:
            # /<data_type>/D-KEY/[start-ts]/[end-ts]/[member-name]
            data = self._createDKeyData(startTimeStamp, endTimeStamp, keyName,
                                        privateKeyBlob, certificateKey)
            result.append(data)

        return result
Exemple #17
0
    def getGroupKey(self, timeSlot, needRegenerate = True):
        """
        Create a group key for the interval into which timeSlot falls. This
        creates a group key if it doesn't exist, and encrypts the key using the
        public key of each eligible member.

        :param float timeSlot: The time slot to cover as milliseconds since
          Jan 1, 1970 UTC.
        :param bool needRegenerate: (optional) needRegenerate should be True if
          this is the first time this method is called, or a member was removed.
          needRegenerate can be False if this is not the first time this method
          is called, or a member was added. If omitted, use True.
        :return: A List of Data packets where the first is the E-KEY data packet
          with the group's public key and the rest are the D-KEY data packets
          with the group's private key encrypted with the public key of each
          eligible member.
        :raises GroupManagerDb.Error: For a database error.
        :raises SecurityException: For an error using the security KeyChain.
        """
        unsortedMemberKeys = {}
        result = []

        # Get the time interval.
        finalInterval = self._calculateInterval(timeSlot, unsortedMemberKeys)
        if finalInterval.isValid() == False:
          return result

        startTimeStamp = Schedule.toIsoString(finalInterval.getStartTime())
        endTimeStamp = Schedule.toIsoString(finalInterval.getEndTime())

        # Generate the private and public keys.
        eKeyName = Name(self._namespace)
        eKeyName.append(Encryptor.NAME_COMPONENT_E_KEY).append(
          startTimeStamp).append(endTimeStamp)

        if not needRegenerate and self._database.hasEKey(eKeyName):
            (publicKeyBlob, privateKeyBlob) = self._getEKey(eKeyName)
        else:
            (privateKeyBlob, publicKeyBlob) = self._generateKeyPair()
            if self._database.hasEKey(eKeyName):
                self._deleteEKey(eKeyName)
            self._addEKey(eKeyName, publicKeyBlob, privateKeyBlob)

        # Add the first element to the result.
        # The E-KEY (public key) data packet name convention is:
        # /<data_type>/E-KEY/[start-ts]/[end-ts]
        data = self._createEKeyData(startTimeStamp, endTimeStamp, publicKeyBlob)
        result.append(data)

        # Encrypt the private key with the public key from each member's certificate.
        # Sort the key names.
        for keyName in sorted(unsortedMemberKeys.keys()):
          certificateKey = unsortedMemberKeys[keyName]

          # Generate the name of the packet.
          # The D-KEY (private key) data packet name convention is:
          # /<data_type>/D-KEY/[start-ts]/[end-ts]/[member-name]
          data = self._createDKeyData(
            startTimeStamp, endTimeStamp, keyName, privateKeyBlob, certificateKey)
          result.append(data)

        return result
Exemple #18
0
    def createContentKey(self, timeSlot, onEncryptedKeys, onError=defaultOnError):
        """
        Create the content key corresponding to the timeSlot. This first checks
        if the content key exists. For an existing content key, this returns the
        content key name directly. If the key does not exist, this creates one
        and encrypts it using the corresponding E-KEYs. The encrypted content
        keys are passed to the onEncryptedKeys callback.

        :param float timeSlot: The time slot as milliseconds since Jan 1,
          1970 UTC.
        :param onEncryptedKeys: If this creates a content key, then this calls
          onEncryptedKeys(keys) where keys is a list of encrypted content key
          Data packets. If onEncryptedKeys is None, this does not use it.
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onEncryptedKeys: function object
        :param onError: (optional) This calls  errorCode, message) for an
          error, where errorCode is from EncryptError.ErrorCode and message is a
          str. If omitted, use a default callback which does nothing.
          NOTE: The library will log any exceptions raised by this callback, but
          for better error handling the callback should catch and properly
          handle any exceptions.
        :type onError: function object
        :return: The content key name.
        :rtype: Name
        """
        hourSlot = Producer._getRoundedTimeSlot(timeSlot)

        # Create the content key name.
        contentKeyName = Name(self._namespace)
        contentKeyName.append(Encryptor.NAME_COMPONENT_C_KEY)
        contentKeyName.append(Schedule.toIsoString(hourSlot))

        # Check if we have created the content key before.
        if self._database.hasContentKey(timeSlot):
            # We have created the content key. Return its name directly.
            return contentKeyName

        # We haven't created the content key. Create one and add it into the
        # database.
        aesParams = AesKeyParams(128)
        contentKeyBits = AesAlgorithm.generateKey(aesParams).getKeyBits()
        self._database.addContentKey(timeSlot, contentKeyBits)

        # Now we need to retrieve the E-KEYs for content key encryption.
        timeCount = round(timeSlot)
        self._keyRequests[timeCount] = Producer._KeyRequest(len(self._eKeyInfo))
        keyRequest = self._keyRequests[timeCount]

        # Check if the current E-KEYs can cover the content key.
        timeRange = Exclude()
        Producer.excludeAfter(timeRange, Name.Component(Schedule.toIsoString(timeSlot)))
        # Send interests for all nodes in the tree.
        for keyName in self._eKeyInfo:
            # For each current E-KEY.
            keyInfo = self._eKeyInfo[keyName]
            if timeSlot < keyInfo.beginTimeSlot or timeSlot >= keyInfo.endTimeSlot:
                # The current E-KEY cannot cover the content key, so retrieve one.
                keyRequest.repeatAttempts[keyName] = 0
                self._sendKeyInterest(
                    Interest(keyName).setExclude(timeRange).setChildSelector(1), timeSlot, onEncryptedKeys, onError
                )
            else:
                # The current E-KEY can cover the content key.
                # Encrypt the content key directly.
                eKeyName = Name(keyName)
                eKeyName.append(Schedule.toIsoString(keyInfo.beginTimeSlot))
                eKeyName.append(Schedule.toIsoString(keyInfo.endTimeSlot))
                self._encryptContentKey(keyInfo.keyBits, eKeyName, timeSlot, onEncryptedKeys, onError)

        return contentKeyName