aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pySim/esim/saip/data_source.py90
-rwxr-xr-xtests/test_esim_saip.py43
2 files changed, 133 insertions, 0 deletions
diff --git a/pySim/esim/saip/data_source.py b/pySim/esim/saip/data_source.py
new file mode 100644
index 0000000..0e14ad8
--- /dev/null
+++ b/pySim/esim/saip/data_source.py
@@ -0,0 +1,90 @@
+# Data sources: Provding data for profile personalization
+#
+# (C) 2024 by Harald Welte <laforge@osmocom.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import abc
+import secrets
+
+from Cryptodome.Random import get_random_bytes
+
+class DataSource(abc.ABC):
+ """Base class for something that can provide data during a personalization process."""
+
+ @abc.abstractmethod
+ def generate_one(self):
+ pass
+
+
+class DataSourceFixed(DataSource):
+ """A data source that provides a fixed value (of any type).
+
+ Parameters:
+ fixed_value: The fixed value that shall be used during each data generation
+ """
+ def __init__(self, fixed_value, **kwargs):
+ self.fixed_value = fixed_value
+ super().__init__(**kwargs)
+
+ def generate_one(self):
+ return self.fixed_value
+
+
+class DataSourceIncrementing(DataSource):
+ """A data source that provides incrementing integer numbers.
+
+ Parameters:
+ base_value: The start value (value returned during first data generation)
+ step_size: Increment step size (Default: 1)
+ """
+ def __init__(self, base_value: int, **kwargs):
+ self.base_value = int(base_value)
+ self.step_size = kwargs.pop('step_size', 1)
+ self.i = 0
+ super().__init__(**kwargs)
+
+ def generate_one(self):
+ val = self.base_value + self.i
+ self.i += self.step_size
+ return val
+
+
+class DataSourceRandomBytes(DataSource):
+ """A data source that provides a configurable number of random bytes.
+
+ Parameters:
+ size: Number of bytes to generate each turn
+ """
+ def __init__(self, size: int, **kwargs):
+ self.size = size
+ super().__init__(**kwargs)
+
+ def generate_one(self):
+ return get_random_bytes(self.size)
+
+
+class DataSourceRandomUInt(DataSource):
+ """A data source that provides a configurable unsigned integer value.
+
+ Parameters:
+ below: Number one greater than the maximum permitted random unsigned integer
+ """
+ def __init__(self, below: int, **kwargs):
+ self.below = below
+ super().__init__(**kwargs)
+
+ def generate_one(self):
+ return secrets.randbelow(self.below)
+
diff --git a/tests/test_esim_saip.py b/tests/test_esim_saip.py
index a70c149..51017fb 100755
--- a/tests/test_esim_saip.py
+++ b/tests/test_esim_saip.py
@@ -21,6 +21,7 @@ import copy
from pySim.utils import h2b, b2h
from pySim.esim.saip import *
+from pySim.esim.saip.data_source import *
from pySim.esim.saip.personalization import *
from pprint import pprint as pp
@@ -64,5 +65,47 @@ class SaipTest(unittest.TestCase):
pes.to_der()
+class DataSourceTest(unittest.TestCase):
+ def test_fixed(self):
+ FIXED = b'\x01\x02\x03'
+ ds = DataSourceFixed(FIXED)
+ self.assertEqual(ds.generate_one(), FIXED)
+ self.assertEqual(ds.generate_one(), FIXED)
+ self.assertEqual(ds.generate_one(), FIXED)
+
+ def test_incrementing(self):
+ BASE_VALUE = 100
+ ds = DataSourceIncrementing(BASE_VALUE)
+ self.assertEqual(ds.generate_one(), BASE_VALUE)
+ self.assertEqual(ds.generate_one(), BASE_VALUE+1)
+ self.assertEqual(ds.generate_one(), BASE_VALUE+2)
+ self.assertEqual(ds.generate_one(), BASE_VALUE+3)
+
+ def test_incrementing_step3(self):
+ BASE_VALUE = 300
+ ds = DataSourceIncrementing(BASE_VALUE, step_size=3)
+ self.assertEqual(ds.generate_one(), BASE_VALUE)
+ self.assertEqual(ds.generate_one(), BASE_VALUE+3)
+ self.assertEqual(ds.generate_one(), BASE_VALUE+6)
+
+ def test_random(self):
+ ds = DataSourceRandomBytes(8)
+ res = []
+ for i in range(0,100):
+ res.append(ds.generate_one())
+ for r in res:
+ self.assertEqual(len(r), 8)
+ # ensure no duplicates exist
+ self.assertEqual(len(set(res)), len(res))
+
+ def test_random_int(self):
+ ds = DataSourceRandomUInt(below=256)
+ res = []
+ for i in range(0,100):
+ res.append(ds.generate_one())
+ for r in res:
+ self.assertTrue(r < 256)
+
+
if __name__ == "__main__":
unittest.main()