Skip to content

Killing Security Mutants #1025

Description

@MartinThoma

Mutation testing applies common mistakes to the codebase and checks if the tests capture them. Those changes are called "mutations" (or mutants). Killing a mutant means to add a test which would fail if the mutation is applied.

_writer.py::encrypt (V2)

--- PyPDF2/_writer.py
+++ PyPDF2/_writer.py
@@ -709,7 +709,7 @@
         encrypt[NameObject(SA.FILTER)] = NameObject("/Standard")
         encrypt[NameObject("/V")] = NumberObject(V)
         if V == 2:
-            encrypt[NameObject(SA.LENGTH)] = NumberObject(keylen * 8)
+            encrypt[NameObject(SA.LENGTH)] = NumberObject(keylen * 9)
         encrypt[NameObject(ED.R)] = NumberObject(rev)
         encrypt[NameObject(ED.O)] = ByteStringObject(O)
         encrypt[NameObject(ED.U)] = ByteStringObject(U)

Mutant #2325

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -78,7 +78,7 @@
     m.update(id1_entry.original_bytes)
     # 6. (Revision 3 or greater) If document metadata is not being encrypted,
     # pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
-    if rev >= 3 and not metadata_encrypt:
+    if rev > 3 and not metadata_encrypt:
         m.update(b"\xff\xff\xff\xff")
     # 7. Finish the hash.
     md5_hash = m.digest()

Mutant 2326

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -78,7 +78,7 @@
     m.update(id1_entry.original_bytes)
     # 6. (Revision 3 or greater) If document metadata is not being encrypted,
     # pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
-    if rev >= 3 and not metadata_encrypt:
+    if rev >= 4 and not metadata_encrypt:
         m.update(b"\xff\xff\xff\xff")
     # 7. Finish the hash.
     md5_hash = m.digest()

Mutant 2337

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -106,7 +106,7 @@
     key = _alg33_1(owner_pwd, rev, keylen)
     # 5. Pad or truncate the user password string as described in step 1 of
     # algorithm 3.2.
-    user_pwd_bytes = b_((user_pwd + str_(_encryption_padding))[:32])
+    user_pwd_bytes = b_((user_pwd + str_(_encryption_padding))[:33])
     # 6. Encrypt the result of step 5, using an RC4 encryption function with
     # the encryption key obtained in step 4.
     val = RC4_encrypt(key, user_pwd_bytes)

Mutant 2340 ✔️

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -116,7 +116,7 @@
     # taking each byte of the encryption key obtained in step 4 and performing
     # an XOR operation between that byte and the single-byte value of the
     # iteration counter (from 1 to 19).
-    if rev >= 3:
+    if rev > 3:
         for i in range(1, 20):
             new_key = ""
             for key_char in key:

Mutant 2341 ✔️

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -116,7 +116,7 @@
     # taking each byte of the encryption key obtained in step 4 and performing
     # an XOR operation between that byte and the single-byte value of the
     # iteration counter (from 1 to 19).
-    if rev >= 3:
+    if rev >= 4:
         for i in range(1, 20):
             new_key = ""
             for key_char in key:

Mutant 2342 ✔️

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -117,7 +117,7 @@
     # an XOR operation between that byte and the single-byte value of the
     # iteration counter (from 1 to 19).
     if rev >= 3:
-        for i in range(1, 20):
+        for i in range(2, 20):
             new_key = ""
             for key_char in key:
                 new_key += chr(ord_(key_char) ^ i)

Mutant 2343

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -117,7 +117,7 @@
     # an XOR operation between that byte and the single-byte value of the
     # iteration counter (from 1 to 19).
     if rev >= 3:
-        for i in range(1, 20):
+        for i in range(1, 21):
             new_key = ""
             for key_char in key:
                 new_key += chr(ord_(key_char) ^ i)

Mutant 2383 ✔️

--- PyPDF2/_security.py
+++ PyPDF2/_security.py
@@ -226,7 +226,7 @@
 
 
 def RC4_encrypt(key: Union[str, bytes], plaintext: bytes) -> bytes:  # TODO
-    S = list(range(256))
+    S = list(range(257))
     j = 0
     for i in range(256):
         j = (j + S[i] + ord_(key[i % len(key)])) % 256

Metadata

Metadata

Assignees

No one assigned

    Labels

    is-maintenanceAnything that is just internal: Simplifying code, syntax changes, updating docs, speed improvementsnf-testingNon-functional change: Testing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions