Skip to content

Commit f54d88f

Browse files
committed
cloudvision/cvlib: Update doType7Obfuscation and add tests
- Make salt(random value if not provided), obf(default value if not provided) parameter optional in doType7Obfuscation. - Add Unit Tests for doType7Obfuscation. Closes: BUG852371 Change-Id: I3af269821645bc84941ca2200638bad8e16b3b03
1 parent c2e1197 commit f54d88f

File tree

2 files changed

+85
-13
lines changed

2 files changed

+85
-13
lines changed

cloudvision/cvlib/utils.py

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import re
66
import crypt
7+
import random
78
from typing import Any, Dict
89
from json import loads
910

@@ -65,28 +66,45 @@ def extractJSONEncodedListArg(listArg: str):
6566
return extractedList
6667

6768

68-
def doType7Obfuscation(plaintext: str, salt: int, obf: str):
69+
OBFUSCATOR = "dsfd;kfoA,.iyewrkldJKDHSUBsgvca69834ncxv9873254k;fg87"
70+
71+
72+
def doType7Obfuscation(plaintext: str, salt: int | None = None, obf: str = ""):
6973
"""
7074
Perform Type 7 password obfuscation using XOR encoding.
7175
7276
Args:
7377
plaintext (str): The plaintext password to obfuscate.
74-
salt (int): The salt value (0-99) to use for obfuscation.
75-
obf (str): The obfuscator string to use for obfuscation.
78+
salt (int | None): The salt value (0-15). If None, a random salt is generated.
79+
obf (str): The obfuscator string for XOR encoding. If empty,
80+
a default obfuscator is used.
7681
7782
Returns:
78-
The obfuscated password as a string.
83+
The obfuscated password prefixed with the 2-digit salt,
84+
or empty string if plaintext is empty.
7985
"""
80-
assert 0 <= salt < 100
8186
if not plaintext:
87+
# If the password is empty, return an empty string without the salt
8288
return plaintext
83-
result = f"{salt:02d}"
84-
obfsize = len(obf)
85-
for i, x in enumerate(plaintext):
86-
y = obf[(i + salt) % obfsize]
87-
key = ord(x) ^ ord(y)
88-
result += f'{key:02X}'
89-
return result
89+
90+
if salt is None:
91+
salt = random.randint(0, 15)
92+
93+
if salt < 0 or salt > 15:
94+
raise ValueError("Salt must be between 0 and 15")
95+
96+
if not obf:
97+
obf = OBFUSCATOR
98+
99+
obf_bytes = obf.encode("UTF-8")
100+
plaintext_bytes = plaintext.encode("UTF-8")
101+
102+
result_bytes = bytearray()
103+
for i, char_byte in enumerate(plaintext_bytes):
104+
key_byte = obf_bytes[(i + salt) % len(obf_bytes)]
105+
result_bytes.append(char_byte ^ key_byte)
106+
107+
return f"{salt:02d}{result_bytes.hex().upper()}"
90108

91109

92110
def doSHA512Hashing(plaintext: str, salt: str):

test/cvlib/context/test_utils.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import pytest
66

7-
from cloudvision.cvlib.utils import doSHA512Hashing
7+
from cloudvision.cvlib.utils import doSHA512Hashing, doType7Obfuscation
88

99

1010
sha512Cases = [
@@ -34,3 +34,57 @@
3434
def test_sha512_hashing(input, salt, expected):
3535
actual = doSHA512Hashing(input, salt)
3636
assert actual == expected
37+
38+
39+
type7ObfuscationCases = [
40+
# Success cases (exception=False)
41+
pytest.param("", 0, None, "", False, id="empty_input"),
42+
pytest.param("password", 10, None, "105E080A16001D1908", False, id="base_case"),
43+
pytest.param("password", 0, None, "00141215174C04140B", False, id="salt_zero"),
44+
pytest.param("password", 15, None, "15020A1F173D24362C", False, id="salt_fifteen"),
45+
pytest.param("茶", 10, None, "10C6E5CF", False, id="unicode_input"),
46+
pytest.param(
47+
"password",
48+
10,
49+
"ABCDEFGHIJKLMNOPQRST",
50+
"103B2D3E3D383F2336",
51+
False,
52+
id="custom_obfuscator",
53+
),
54+
pytest.param(
55+
"password",
56+
10,
57+
"茶",
58+
"10FCD79BFFC187FED2",
59+
False,
60+
id="unicode_obfuscator",
61+
),
62+
# Error cases (exception=True)
63+
pytest.param(
64+
"password",
65+
-1,
66+
None,
67+
"Salt must be between 0 and 15",
68+
True,
69+
id="salt_negative",
70+
),
71+
pytest.param(
72+
"password",
73+
16,
74+
None,
75+
"Salt must be between 0 and 15",
76+
True,
77+
id="salt_too_large",
78+
),
79+
]
80+
81+
82+
@pytest.mark.parametrize("input, salt, obf, expected, exception", type7ObfuscationCases)
83+
def test_type7_obfuscation(input, salt, obf, expected, exception):
84+
if exception:
85+
with pytest.raises(ValueError) as exc_info:
86+
doType7Obfuscation(input, salt, obf)
87+
assert expected in str(exc_info.value), "Unexpected exception"
88+
else:
89+
actual = doType7Obfuscation(input, salt, obf)
90+
assert actual == expected, "Response is not expected"

0 commit comments

Comments
 (0)