Skip to content

Commit

Permalink
Provide the crypt module for backward compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
hroncok committed Apr 29, 2024
1 parent a0f2024 commit e5dc03d
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 33 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ name = "crypt_r"
version = "3.12.3"

[tool.setuptools]
py-modules = ["crypt_r"]
py-modules = ["crypt_r", "crypt"]
package-dir = {"" = "src"}
3 changes: 3 additions & 0 deletions src/crypt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Wrapper around crypt_r to provide the old name."""
from crypt_r import *
from crypt_r import _saltchars # for tests
72 changes: 40 additions & 32 deletions tests/test_crypt_r.py
Original file line number Diff line number Diff line change
@@ -1,88 +1,96 @@
import sys
import unittest

import crypt_r as crypt
import crypt_r


class CryptTestCase(unittest.TestCase):
class CryptRTestCase(unittest.TestCase):
crypt = crypt_r

def test_crypt(self):
cr = crypt.crypt('mypassword')
cr2 = crypt.crypt('mypassword', cr)
cr = self.crypt.crypt('mypassword')
cr2 = self.crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)
cr = crypt.crypt('mypassword', 'ab')
cr = self.crypt.crypt('mypassword', 'ab')
if cr is not None:
cr2 = crypt.crypt('mypassword', cr)
cr2 = self.crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)

def test_salt(self):
self.assertEqual(len(crypt._saltchars), 64)
for method in crypt.methods:
salt = crypt.mksalt(method)
self.assertEqual(len(self.crypt._saltchars), 64)
for method in self.crypt.methods:
salt = self.crypt.mksalt(method)
self.assertIn(len(salt) - method.salt_chars, {0, 1, 3, 4, 6, 7})
if method.ident:
self.assertIn(method.ident, salt[:len(salt)-method.salt_chars])

def test_saltedcrypt(self):
for method in crypt.methods:
cr = crypt.crypt('assword', method)
for method in self.crypt.methods:
cr = self.crypt.crypt('assword', method)
self.assertEqual(len(cr), method.total_size)
cr2 = crypt.crypt('assword', cr)
cr2 = self.crypt.crypt('assword', cr)
self.assertEqual(cr2, cr)
cr = crypt.crypt('assword', crypt.mksalt(method))
cr = self.crypt.crypt('assword', self.crypt.mksalt(method))
self.assertEqual(len(cr), method.total_size)

def test_methods(self):
self.assertTrue(len(crypt.methods) >= 1)
self.assertTrue(len(self.crypt.methods) >= 1)
if sys.platform.startswith('openbsd'):
self.assertEqual(crypt.methods, [crypt.METHOD_BLOWFISH])
self.assertEqual(self.crypt.methods, [self.crypt.METHOD_BLOWFISH])
else:
self.assertEqual(crypt.methods[-1], crypt.METHOD_CRYPT)
self.assertEqual(self.crypt.methods[-1], self.crypt.METHOD_CRYPT)

@unittest.skipUnless(
crypt.METHOD_SHA256 in crypt.methods or crypt.METHOD_SHA512 in crypt.methods,
'requires support of SHA-2',
)
def test_sha2_rounds(self):
for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512):
for method in (self.crypt.METHOD_SHA256, self.crypt.METHOD_SHA512):
for rounds in 1000, 10_000, 100_000:
salt = crypt.mksalt(method, rounds=rounds)
salt = self.crypt.mksalt(method, rounds=rounds)
self.assertIn('$rounds=%d$' % rounds, salt)
self.assertEqual(len(salt) - method.salt_chars,
11 + len(str(rounds)))
cr = crypt.crypt('mypassword', salt)
cr = self.crypt.crypt('mypassword', salt)
self.assertTrue(cr)
cr2 = crypt.crypt('mypassword', cr)
cr2 = self.crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)

@unittest.skipUnless(
crypt.METHOD_BLOWFISH in crypt.methods, 'requires support of Blowfish'
)
def test_blowfish_rounds(self):
for log_rounds in range(4, 11):
salt = crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1 << log_rounds)
salt = self.crypt.mksalt(self.crypt.METHOD_BLOWFISH, rounds=1 << log_rounds)
self.assertIn('$%02d$' % log_rounds, salt)
self.assertIn(len(salt) - crypt.METHOD_BLOWFISH.salt_chars, {6, 7})
cr = crypt.crypt('mypassword', salt)
self.assertIn(len(salt) - self.crypt.METHOD_BLOWFISH.salt_chars, {6, 7})
cr = self.crypt.crypt('mypassword', salt)
self.assertTrue(cr)
cr2 = crypt.crypt('mypassword', cr)
cr2 = self.crypt.crypt('mypassword', cr)
self.assertEqual(cr2, cr)

def test_invalid_rounds(self):
for method in (crypt.METHOD_SHA256, crypt.METHOD_SHA512,
crypt.METHOD_BLOWFISH):
for method in (self.crypt.METHOD_SHA256, self.crypt.METHOD_SHA512,
self.crypt.METHOD_BLOWFISH):
with self.assertRaises(TypeError):
crypt.mksalt(method, rounds='4096')
self.crypt.mksalt(method, rounds='4096')
with self.assertRaises(TypeError):
crypt.mksalt(method, rounds=4096.0)
self.crypt.mksalt(method, rounds=4096.0)
for rounds in (0, 1, -1, 1<<999):
with self.assertRaises(ValueError):
crypt.mksalt(method, rounds=rounds)
self.crypt.mksalt(method, rounds=rounds)
with self.assertRaises(ValueError):
crypt.mksalt(crypt.METHOD_BLOWFISH, rounds=1000)
for method in (crypt.METHOD_CRYPT, crypt.METHOD_MD5):
self.crypt.mksalt(self.crypt.METHOD_BLOWFISH, rounds=1000)
for method in (self.crypt.METHOD_CRYPT, self.crypt.METHOD_MD5):
with self.assertRaisesRegex(ValueError, 'support'):
crypt.mksalt(method, rounds=4096)
self.crypt.mksalt(method, rounds=4096)


if sys.version_info >= (3, 13):
import crypt

class CryptTestCase(CryptRTestCase):
crypt = crypt


if __name__ == "__main__":
Expand Down

0 comments on commit e5dc03d

Please sign in to comment.