- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
1031 lines
30 KiB
Python
1031 lines
30 KiB
Python
"""
|
|
Java javax.crypto APIs implemented in Python.
|
|
javax.crypto package - Cipher, KeyGenerator, Mac, KeyAgreement, SecretKey, etc.
|
|
Wraps Python cryptography library.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from typing import List, Optional, Any
|
|
|
|
# Optional cryptography dependency
|
|
try:
|
|
from cryptography.fernet import Fernet as _Fernet
|
|
from cryptography.hazmat.primitives.ciphers import Cipher as _Cipher, algorithms as _algorithms, modes as _modes
|
|
from cryptography.hazmat.primitives import hashes as _hashes, hmac as _hmac, padding as _padding
|
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC as _PBKDF2HMAC
|
|
HAS_CRYPTOGRAPHY = True
|
|
except ImportError:
|
|
HAS_CRYPTOGRAPHY = False
|
|
|
|
__all__ = [
|
|
"Cipher", "KeyGenerator", "SecretKey", "SecretKeySpec",
|
|
"Mac", "KeyAgreement", "ExemptionMechanism",
|
|
"EncryptedPrivateKeyInfo", "SealedObject", "NullCipher",
|
|
"PBEParameterSpec", "IvParameterSpec", "OAEPParameterSpec",
|
|
"PSource", "MGF1ParameterSpec", "DESedeKeySpec", "DESKeySpec",
|
|
"SecretKeyFactory", "CipherInputStream", "CipherOutputStream",
|
|
"BadPaddingException", "IllegalBlockSizeException",
|
|
"NoSuchPaddingException", "ShortBufferException",
|
|
]
|
|
|
|
|
|
# ============================================================
|
|
# Exceptions
|
|
# ============================================================
|
|
|
|
class BadPaddingException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Bad padding")
|
|
self._message = message
|
|
|
|
def toString(self) -> str:
|
|
return f"BadPaddingException: {self._message}" if self._message else "BadPaddingException"
|
|
|
|
def equals(self, other) -> bool:
|
|
return isinstance(other, BadPaddingException) and self._message == other._message
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._message) & 0x7FFFFFFF
|
|
|
|
|
|
class IllegalBlockSizeException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Illegal block size")
|
|
self._message = message
|
|
|
|
def toString(self) -> str:
|
|
return f"IllegalBlockSizeException: {self._message}" if self._message else "IllegalBlockSizeException"
|
|
|
|
def equals(self, other) -> bool:
|
|
return isinstance(other, IllegalBlockSizeException) and self._message == other._message
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._message) & 0x7FFFFFFF
|
|
|
|
|
|
class NoSuchPaddingException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "No such padding")
|
|
self._message = message
|
|
|
|
def toString(self) -> str:
|
|
return f"NoSuchPaddingException: {self._message}" if self._message else "NoSuchPaddingException"
|
|
|
|
def equals(self, other) -> bool:
|
|
return isinstance(other, NoSuchPaddingException) and self._message == other._message
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._message) & 0x7FFFFFFF
|
|
|
|
|
|
class ShortBufferException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Output buffer too short")
|
|
self._message = message
|
|
|
|
def toString(self) -> str:
|
|
return f"ShortBufferException: {self._message}" if self._message else "ShortBufferException"
|
|
|
|
def equals(self, other) -> bool:
|
|
return isinstance(other, ShortBufferException) and self._message == other._message
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._message) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# SecretKey
|
|
# ============================================================
|
|
|
|
class SecretKey(Stub):
|
|
"""
|
|
javax.crypto.SecretKey
|
|
A secret (symmetric) key.
|
|
"""
|
|
serialVersionUID: int = -4795878709
|
|
|
|
def __init__(self, encoded: bytes = None, algorithm: str = None):
|
|
super().__init__()
|
|
self._encoded = encoded or b''
|
|
self._algorithm = algorithm or "RAW"
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getFormat(self) -> str:
|
|
return "RAW"
|
|
|
|
def getEncoded(self) -> bytes:
|
|
return self._encoded
|
|
|
|
def toString(self) -> str:
|
|
return f"SecretKey@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, SecretKey):
|
|
return self._encoded == other._encoded and self._algorithm == other._algorithm
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash((bytes(self._encoded), self._algorithm)) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# SecretKeySpec
|
|
# ============================================================
|
|
|
|
class SecretKeySpec(SecretKey):
|
|
"""
|
|
javax.crypto.spec.SecretKeySpec
|
|
A secret key specification.
|
|
"""
|
|
|
|
def __init__(self, key: bytes, algorithm: str):
|
|
super().__init__(key, algorithm)
|
|
self._key = key
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getFormat(self) -> str:
|
|
return "RAW"
|
|
|
|
def getEncoded(self) -> bytes:
|
|
return self._key
|
|
|
|
def toString(self) -> str:
|
|
return f"SecretKeySpec@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, SecretKeySpec):
|
|
return self._key == other._key and self._algorithm == other._algorithm
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash((bytes(self._key), self._algorithm)) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Cipher
|
|
# ============================================================
|
|
|
|
class Cipher(Stub):
|
|
"""
|
|
javax.crypto.Cipher
|
|
Engine for encryption/decryption.
|
|
"""
|
|
ENCRYPT_MODE: int = 1
|
|
DECRYPT_MODE: int = 2
|
|
WRAP_MODE: int = 3
|
|
UNWRAP_MODE: int = 4
|
|
PUBLIC_KEY: int = 1
|
|
PRIVATE_KEY: int = 2
|
|
SECRET_KEY: int = 3
|
|
|
|
def __init__(self, transformation: str = None):
|
|
super().__init__()
|
|
self._transformation = transformation
|
|
self._opmode = None
|
|
self._key = None
|
|
self._iv = None
|
|
self._provider = None
|
|
|
|
@staticmethod
|
|
def getInstance(transformation: str) -> "Cipher":
|
|
return Cipher(transformation)
|
|
|
|
def init(self, opmode: int, key: Any, params: Any = None, random: Any = None):
|
|
"""Initializes this cipher with a key and optional parameters."""
|
|
self._opmode = opmode
|
|
self._key = key
|
|
if params and hasattr(params, 'getIV'):
|
|
self._iv = params.getIV()
|
|
|
|
def doFinal(self, input_data: bytes = None) -> bytes:
|
|
"""Performs the final encryption/decryption operation."""
|
|
if input_data is None:
|
|
return b''
|
|
if not HAS_CRYPTOGRAPHY:
|
|
# Fallback simple XOR for demonstration
|
|
if self._key and hasattr(self._key, 'getEncoded'):
|
|
key_bytes = self._key.getEncoded()
|
|
if key_bytes:
|
|
result = bytearray()
|
|
for i, b in enumerate(input_data):
|
|
result.append(b ^ key_bytes[i % len(key_bytes)])
|
|
return bytes(result)
|
|
return input_data
|
|
|
|
# Try using cryptography library
|
|
try:
|
|
if self._key and hasattr(self._key, 'getEncoded'):
|
|
key_bytes = self._key.getEncoded()
|
|
if self._transformation and "AES" in self._transformation.upper():
|
|
if len(key_bytes) in (16, 24, 32):
|
|
if self._opmode == Cipher.ENCRYPT_MODE:
|
|
from cryptography.hazmat.primitives.ciphers import Cipher as _CryptCipher, algorithms as _alg, modes as _mod
|
|
iv = self._iv or b'\x00' * 16
|
|
c = _CryptCipher(_alg.AES(key_bytes), _mod.CBC(iv))
|
|
encryptor = c.encryptor()
|
|
padder = _padding.PKCS7(128).padder()
|
|
padded = padder.update(input_data) + padder.finalize()
|
|
return encryptor.update(padded) + encryptor.finalize()
|
|
elif self._opmode == Cipher.DECRYPT_MODE:
|
|
iv = self._iv or b'\x00' * 16
|
|
c = _CryptCipher(_alg.AES(key_bytes), _mod.CBC(iv))
|
|
decryptor = c.decryptor()
|
|
padded = decryptor.update(input_data) + decryptor.finalize()
|
|
unpadder = _padding.PKCS7(128).unpadder()
|
|
return unpadder.update(padded) + unpadder.finalize()
|
|
except Exception:
|
|
pass
|
|
return input_data
|
|
|
|
def update(self, input_data: bytes) -> bytes:
|
|
"""Continues a multi-part encryption/decryption operation."""
|
|
return input_data
|
|
|
|
def wrap(self, key: Any) -> bytes:
|
|
"""Wraps a key (stub)."""
|
|
if isinstance(key, SecretKey):
|
|
return key.getEncoded()
|
|
return b''
|
|
|
|
def unwrap(self, wrapped_key: bytes, wrapped_key_algorithm: str, wrapped_key_type: int) -> Any:
|
|
"""Unwraps a key (stub)."""
|
|
return SecretKey(wrapped_key, wrapped_key_algorithm)
|
|
|
|
def getBlockSize(self) -> int:
|
|
"""Returns the block size (bytes)."""
|
|
if self._transformation and "AES" in self._transformation.upper():
|
|
return 16
|
|
if self._transformation and "DES" in self._transformation.upper():
|
|
return 8
|
|
return 0
|
|
|
|
def getIV(self) -> Optional[bytes]:
|
|
return self._iv
|
|
|
|
def getParameters(self):
|
|
return None
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._transformation or "NONE"
|
|
|
|
def getProvider(self):
|
|
return self._provider
|
|
|
|
def getExemptionMechanism(self):
|
|
return None
|
|
|
|
def getOutputSize(self, input_len: int) -> int:
|
|
"""Returns the output buffer size for a given input length."""
|
|
bs = self.getBlockSize()
|
|
if bs > 0:
|
|
return input_len + (bs - input_len % bs)
|
|
return input_len
|
|
|
|
@staticmethod
|
|
def getMaxAllowedKeyLength(transformation: str) -> int:
|
|
"""Returns the maximum key length for the given transformation."""
|
|
return 2147483647 # Integer.MAX_VALUE
|
|
|
|
def toString(self) -> str:
|
|
return f"Cipher@{hex(id(self))}[algorithm={self._transformation}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# NullCipher
|
|
# ============================================================
|
|
|
|
class NullCipher(Cipher):
|
|
"""
|
|
javax.crypto.NullCipher
|
|
A cipher that performs no transformation (identity).
|
|
"""
|
|
def __init__(self):
|
|
super().__init__("NULL")
|
|
|
|
def getBlockSize(self) -> int:
|
|
return 1
|
|
|
|
def getOutputSize(self, input_len: int) -> int:
|
|
return input_len
|
|
|
|
def getIV(self) -> Optional[bytes]:
|
|
return None
|
|
|
|
def getParameters(self):
|
|
return None
|
|
|
|
def getExemptionMechanism(self):
|
|
return None
|
|
|
|
def update(self, input_data: bytes) -> bytes:
|
|
return input_data
|
|
|
|
def doFinal(self, input_data: bytes = None) -> bytes:
|
|
return input_data if input_data else b''
|
|
|
|
def toString(self) -> str:
|
|
return "NullCipher"
|
|
|
|
|
|
# ============================================================
|
|
# KeyGenerator
|
|
# ============================================================
|
|
|
|
class KeyGenerator(Stub):
|
|
"""
|
|
javax.crypto.KeyGenerator
|
|
Key generator for symmetric algorithms.
|
|
"""
|
|
|
|
def __init__(self, algorithm: str = None):
|
|
super().__init__()
|
|
self._algorithm = algorithm or "AES"
|
|
self._provider = None
|
|
self._key_size = 128
|
|
|
|
@staticmethod
|
|
def getInstance(algorithm: str) -> "KeyGenerator":
|
|
return KeyGenerator(algorithm)
|
|
|
|
def init(self, key_size_or_random: Any, random: Any = None):
|
|
"""Initializes the key generator."""
|
|
if isinstance(key_size_or_random, int):
|
|
self._key_size = key_size_or_random
|
|
elif key_size_or_random is not None and hasattr(key_size_or_random, 'nextBytes'):
|
|
pass
|
|
|
|
def generateKey(self) -> SecretKey:
|
|
"""Generates a secret key."""
|
|
import os
|
|
key_bytes = os.urandom(self._key_size // 8)
|
|
return SecretKey(key_bytes, self._algorithm)
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getProvider(self):
|
|
return self._provider
|
|
|
|
def toString(self) -> str:
|
|
return f"KeyGenerator@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Mac
|
|
# ============================================================
|
|
|
|
class Mac(Stub):
|
|
"""
|
|
javax.crypto.Mac
|
|
Message Authentication Code engine.
|
|
"""
|
|
|
|
def __init__(self, algorithm: str = None):
|
|
super().__init__()
|
|
self._algorithm = algorithm or "HmacSHA256"
|
|
self._provider = None
|
|
self._key = None
|
|
self._hmac = None
|
|
self._initialized = False
|
|
|
|
@staticmethod
|
|
def getInstance(algorithm: str) -> "Mac":
|
|
return Mac(algorithm)
|
|
|
|
def init(self, key: Any, params: Any = None):
|
|
"""Initializes the MAC with a key."""
|
|
self._key = key
|
|
self._initialized = True
|
|
if HAS_CRYPTOGRAPHY and key and hasattr(key, 'getEncoded'):
|
|
key_bytes = key.getEncoded()
|
|
hash_algo = _hashes.SHA256()
|
|
self._hmac = _hmac.HMAC(key_bytes, hash_algo)
|
|
|
|
def update(self, input_data: bytes):
|
|
"""Processes the given byte array."""
|
|
if self._hmac:
|
|
self._hmac.update(input_data)
|
|
|
|
def doFinal(self, input_data: bytes = None) -> bytes:
|
|
"""Finishes the MAC operation."""
|
|
if self._hmac:
|
|
if input_data:
|
|
self._hmac.update(input_data)
|
|
return self._hmac.finalize()
|
|
if input_data:
|
|
import hashlib
|
|
return hashlib.sha256(input_data).digest()
|
|
return b'\x00' * 32
|
|
|
|
def getMacLength(self) -> int:
|
|
"""Returns the output length of the MAC."""
|
|
return 32 # SHA-256
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getProvider(self):
|
|
return self._provider
|
|
|
|
def reset(self):
|
|
"""Resets the MAC."""
|
|
if self._key and hasattr(self._key, 'getEncoded') and HAS_CRYPTOGRAPHY:
|
|
key_bytes = self._key.getEncoded()
|
|
hash_algo = _hashes.SHA256()
|
|
self._hmac = _hmac.HMAC(key_bytes, hash_algo)
|
|
|
|
def clone(self):
|
|
return Mac(self._algorithm)
|
|
|
|
def toString(self) -> str:
|
|
return f"Mac@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# KeyAgreement
|
|
# ============================================================
|
|
|
|
class KeyAgreement(Stub):
|
|
"""
|
|
javax.crypto.KeyAgreement
|
|
Key agreement protocol engine (e.g., Diffie-Hellman).
|
|
"""
|
|
|
|
def __init__(self, algorithm: str = None):
|
|
super().__init__()
|
|
self._algorithm = algorithm or "DH"
|
|
self._provider = None
|
|
|
|
@staticmethod
|
|
def getInstance(algorithm: str) -> "KeyAgreement":
|
|
return KeyAgreement(algorithm)
|
|
|
|
def init(self, key: Any, params: Any = None):
|
|
"""Initializes this key agreement with a key."""
|
|
pass
|
|
|
|
def doPhase(self, key: Any, last_phase: bool) -> Any:
|
|
"""Executes the next phase of the key agreement."""
|
|
return self
|
|
|
|
def generateSecret(self, shared_secret: Any = None) -> bytes:
|
|
"""Generates the shared secret."""
|
|
import os
|
|
return os.urandom(32)
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getProvider(self):
|
|
return self._provider
|
|
|
|
def toString(self) -> str:
|
|
return f"KeyAgreement@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# ExemptionMechanism
|
|
# ============================================================
|
|
|
|
class ExemptionMechanism(Stub):
|
|
"""
|
|
javax.crypto.ExemptionMechanism
|
|
Exemption mechanism for key recovery.
|
|
"""
|
|
|
|
def __init__(self, algorithm: str = None):
|
|
super().__init__()
|
|
self._algorithm = algorithm or "KeyRecovery"
|
|
self._initialized = False
|
|
|
|
@staticmethod
|
|
def getInstance(algorithm: str) -> "ExemptionMechanism":
|
|
return ExemptionMechanism(algorithm)
|
|
|
|
def init(self, key: Any):
|
|
self._initialized = True
|
|
|
|
def genExemptionBlob(self, input_data: bytes = None) -> bytes:
|
|
return b'\x00' * 32
|
|
|
|
def isCryptoAllowed(self, key: Any) -> bool:
|
|
return True
|
|
|
|
def getOutputSize(self, input_len: int) -> int:
|
|
return input_len
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getProvider(self):
|
|
return None
|
|
|
|
def getName(self) -> str:
|
|
return self._algorithm
|
|
|
|
def toString(self) -> str:
|
|
return f"ExemptionMechanism@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# EncryptedPrivateKeyInfo
|
|
# ============================================================
|
|
|
|
class EncryptedPrivateKeyInfo(Stub):
|
|
"""
|
|
javax.crypto.EncryptedPrivateKeyInfo
|
|
Represents encrypted private key info from PKCS #8.
|
|
"""
|
|
|
|
def __init__(self, alg_params=None, encrypted_data: bytes = None):
|
|
super().__init__()
|
|
self._alg_params = alg_params
|
|
self._encrypted_data = encrypted_data or b''
|
|
|
|
def getAlgParameters(self):
|
|
return self._alg_params
|
|
|
|
def getEncryptedData(self) -> bytes:
|
|
return self._encrypted_data
|
|
|
|
def getEncoded(self) -> bytes:
|
|
return self._encrypted_data
|
|
|
|
def getName(self) -> str:
|
|
return "PKCS#8"
|
|
|
|
def toString(self) -> str:
|
|
return f"EncryptedPrivateKeyInfo@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# SealedObject
|
|
# ============================================================
|
|
|
|
class SealedObject(Stub):
|
|
"""
|
|
javax.crypto.SealedObject
|
|
Enables protection of a serializable object using encryption.
|
|
"""
|
|
|
|
def __init__(self, obj: Any = None, cipher: Cipher = None):
|
|
super().__init__()
|
|
self._encrypted_data = b''
|
|
self._algorithm = "NONE"
|
|
if cipher and obj is not None:
|
|
import pickle
|
|
serialized = pickle.dumps(obj)
|
|
self._encrypted_data = cipher.doFinal(serialized)
|
|
self._algorithm = cipher.getAlgorithm()
|
|
|
|
def getObject(self, cipher_or_key: Any = None) -> Any:
|
|
"""Unseals the object."""
|
|
import pickle
|
|
try:
|
|
if isinstance(cipher_or_key, Cipher):
|
|
decrypted = cipher_or_key.doFinal(self._encrypted_data)
|
|
else:
|
|
decrypted = self._encrypted_data
|
|
return pickle.loads(decrypted)
|
|
except Exception:
|
|
return None
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getEncoded(self) -> bytes:
|
|
return self._encrypted_data
|
|
|
|
def toString(self) -> str:
|
|
return f"SealedObject@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# ParameterSpec classes
|
|
# ============================================================
|
|
|
|
class IvParameterSpec(Stub):
|
|
"""
|
|
javax.crypto.spec.IvParameterSpec
|
|
Initialization vector specification.
|
|
"""
|
|
def __init__(self, iv: bytes):
|
|
super().__init__()
|
|
self._iv = iv
|
|
|
|
def getIV(self) -> bytes:
|
|
return self._iv
|
|
|
|
def toString(self) -> str:
|
|
return f"IvParameterSpec@{hex(id(self))}[iv={self._iv.hex()[:16]}...]"
|
|
|
|
|
|
class PBEParameterSpec(Stub):
|
|
"""
|
|
javax.crypto.spec.PBEParameterSpec
|
|
Password-based encryption parameter specification.
|
|
"""
|
|
def __init__(self, salt: bytes, iteration_count: int):
|
|
super().__init__()
|
|
self._salt = salt
|
|
self._iteration_count = iteration_count
|
|
|
|
def getSalt(self) -> bytes:
|
|
return self._salt
|
|
|
|
def getIterationCount(self) -> int:
|
|
return self._iteration_count
|
|
|
|
def toString(self) -> str:
|
|
return f"PBEParameterSpec@{hex(id(self))}[iterations={self._iteration_count}]"
|
|
|
|
|
|
class PSource(Stub):
|
|
"""
|
|
javax.crypto.spec.PSource
|
|
Source of the label for OAEP padding.
|
|
"""
|
|
class PSpecified(Stub):
|
|
DEFAULT: "PSource.PSpecified" = None
|
|
def __init__(self, value: bytes = b''):
|
|
super().__init__()
|
|
self._value = value
|
|
def getValue(self) -> bytes:
|
|
return self._value
|
|
def toString(self) -> str:
|
|
return "PSpecified"
|
|
|
|
def __init__(self, algorithm: str = None):
|
|
super().__init__()
|
|
self._algorithm = algorithm
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def toString(self) -> str:
|
|
return f"PSource.{self._algorithm}" if self._algorithm else "PSource"
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, PSource):
|
|
return self._algorithm == other._algorithm
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._algorithm) & 0x7FFFFFFF
|
|
|
|
|
|
PSource.PSpecified.DEFAULT = PSource.PSpecified(b'')
|
|
|
|
|
|
class OAEPParameterSpec(Stub):
|
|
"""
|
|
javax.crypto.spec.OAEPParameterSpec
|
|
OAEP padding parameter specification.
|
|
"""
|
|
DEFAULT: "OAEPParameterSpec" = None
|
|
|
|
def __init__(self, digest_algorithm: str = "SHA-256",
|
|
mgf_algorithm: str = "MGF1",
|
|
mgf_parameters: Any = None,
|
|
p_source: PSource = None):
|
|
super().__init__()
|
|
self._digest_algorithm = digest_algorithm
|
|
self._mgf_algorithm = mgf_algorithm
|
|
self._mgf_parameters = mgf_parameters
|
|
self._p_source = p_source or PSource.PSpecified.DEFAULT
|
|
|
|
def getDigestAlgorithm(self) -> str:
|
|
return self._digest_algorithm
|
|
|
|
def getMGFAlgorithm(self) -> str:
|
|
return self._mgf_algorithm
|
|
|
|
def getMGFParameters(self):
|
|
return self._mgf_parameters
|
|
|
|
def getPSource(self) -> PSource:
|
|
return self._p_source
|
|
|
|
def getPSourceAlgorithm(self) -> str:
|
|
return self._p_source.getAlgorithm() if self._p_source else ""
|
|
|
|
def toString(self) -> str:
|
|
return f"OAEPParameterSpec@{hex(id(self))}[digest={self._digest_algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
OAEPParameterSpec.DEFAULT = OAEPParameterSpec()
|
|
|
|
|
|
class MGF1ParameterSpec(Stub):
|
|
"""
|
|
javax.crypto.spec.MGF1ParameterSpec
|
|
MGF1 parameter specification.
|
|
"""
|
|
SHA1: "MGF1ParameterSpec" = None
|
|
SHA224: "MGF1ParameterSpec" = None
|
|
SHA256: "MGF1ParameterSpec" = None
|
|
SHA384: "MGF1ParameterSpec" = None
|
|
SHA512: "MGF1ParameterSpec" = None
|
|
SHA512_224: "MGF1ParameterSpec" = None
|
|
SHA512_256: "MGF1ParameterSpec" = None
|
|
SHA3_224: "MGF1ParameterSpec" = None
|
|
SHA3_256: "MGF1ParameterSpec" = None
|
|
SHA3_384: "MGF1ParameterSpec" = None
|
|
SHA3_512: "MGF1ParameterSpec" = None
|
|
|
|
def __init__(self, digest_algorithm: str = "SHA-1"):
|
|
super().__init__()
|
|
self._digest_algorithm = digest_algorithm
|
|
|
|
def getDigestAlgorithm(self) -> str:
|
|
return self._digest_algorithm
|
|
|
|
def toString(self) -> str:
|
|
return f"MGF1ParameterSpec[{self._digest_algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, MGF1ParameterSpec):
|
|
return self._digest_algorithm == other._digest_algorithm
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._digest_algorithm) & 0x7FFFFFFF
|
|
|
|
|
|
MGF1ParameterSpec.SHA1 = MGF1ParameterSpec("SHA-1")
|
|
MGF1ParameterSpec.SHA224 = MGF1ParameterSpec("SHA-224")
|
|
MGF1ParameterSpec.SHA256 = MGF1ParameterSpec("SHA-256")
|
|
MGF1ParameterSpec.SHA384 = MGF1ParameterSpec("SHA-384")
|
|
MGF1ParameterSpec.SHA512 = MGF1ParameterSpec("SHA-512")
|
|
MGF1ParameterSpec.SHA512_224 = MGF1ParameterSpec("SHA-512/224")
|
|
MGF1ParameterSpec.SHA512_256 = MGF1ParameterSpec("SHA-512/256")
|
|
MGF1ParameterSpec.SHA3_224 = MGF1ParameterSpec("SHA3-224")
|
|
MGF1ParameterSpec.SHA3_256 = MGF1ParameterSpec("SHA3-256")
|
|
MGF1ParameterSpec.SHA3_384 = MGF1ParameterSpec("SHA3-384")
|
|
MGF1ParameterSpec.SHA3_512 = MGF1ParameterSpec("SHA3-512")
|
|
|
|
|
|
class DESedeKeySpec(Stub):
|
|
"""
|
|
javax.crypto.spec.DESedeKeySpec
|
|
Key specification for DES-EDE (Triple DES) keys.
|
|
"""
|
|
DES_EDE_KEY_LEN: int = 24
|
|
|
|
def __init__(self, key: bytes):
|
|
super().__init__()
|
|
self._key = key
|
|
|
|
def getKey(self) -> bytes:
|
|
return self._key
|
|
|
|
@staticmethod
|
|
def isParityAdjusted(key: bytes) -> bool:
|
|
return True
|
|
|
|
def toString(self) -> str:
|
|
return f"DESedeKeySpec@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
class DESKeySpec(Stub):
|
|
"""
|
|
javax.crypto.spec.DESKeySpec
|
|
Key specification for DES keys.
|
|
"""
|
|
DES_KEY_LEN: int = 8
|
|
|
|
def __init__(self, key: bytes):
|
|
super().__init__()
|
|
self._key = key
|
|
|
|
def getKey(self) -> bytes:
|
|
return self._key
|
|
|
|
@staticmethod
|
|
def isParityAdjusted(key: bytes) -> bool:
|
|
return True
|
|
|
|
@staticmethod
|
|
def isWeak(key: bytes) -> bool:
|
|
return False
|
|
|
|
def toString(self) -> str:
|
|
return f"DESKeySpec@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# SecretKeyFactory
|
|
# ============================================================
|
|
|
|
class SecretKeyFactory(Stub):
|
|
"""
|
|
javax.crypto.SecretKeyFactory
|
|
Factory for converting between opaque and transparent keys.
|
|
"""
|
|
|
|
def __init__(self, algorithm: str = None):
|
|
super().__init__()
|
|
self._algorithm = algorithm or "AES"
|
|
self._provider = None
|
|
|
|
@staticmethod
|
|
def getInstance(algorithm: str) -> "SecretKeyFactory":
|
|
return SecretKeyFactory(algorithm)
|
|
|
|
def translateKey(self, key: SecretKey) -> SecretKey:
|
|
return key
|
|
|
|
def generateSecret(self, key_spec: Any) -> SecretKey:
|
|
if isinstance(key_spec, SecretKeySpec):
|
|
return key_spec
|
|
return SecretKey(b'', self._algorithm)
|
|
|
|
def getKeySpec(self, key: SecretKey, key_spec_cls: type) -> Any:
|
|
if key_spec_cls == SecretKeySpec:
|
|
return SecretKeySpec(key.getEncoded(), key.getAlgorithm())
|
|
return key
|
|
|
|
def getAlgorithm(self) -> str:
|
|
return self._algorithm
|
|
|
|
def getProvider(self):
|
|
return self._provider
|
|
|
|
def toString(self) -> str:
|
|
return f"SecretKeyFactory@{hex(id(self))}[algorithm={self._algorithm}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# CipherInputStream
|
|
# ============================================================
|
|
|
|
class CipherInputStream(Stub):
|
|
"""
|
|
javax.crypto.CipherInputStream
|
|
A CipherInputStream is composed of an InputStream and a Cipher.
|
|
"""
|
|
def __init__(self, istream, cipher: Cipher):
|
|
super().__init__()
|
|
self._istream = istream
|
|
self._cipher = cipher
|
|
self._buffer = b''
|
|
|
|
def read(self, b: bytearray = None, off: int = 0, le: int = 0) -> int:
|
|
data = self._istream.read(le) if le else self._istream.read()
|
|
if not data:
|
|
return -1
|
|
decrypted = self._cipher.update(data)
|
|
self._buffer += decrypted
|
|
if b is not None and le > 0:
|
|
n = min(le, len(self._buffer))
|
|
b[off:off + n] = self._buffer[:n]
|
|
self._buffer = self._buffer[n:]
|
|
return n
|
|
return len(data)
|
|
|
|
def available(self) -> int:
|
|
return len(self._buffer)
|
|
|
|
def skip(self, n: int) -> int:
|
|
self._buffer = self._buffer[n:]
|
|
return n
|
|
|
|
def close(self):
|
|
if hasattr(self._istream, 'close'):
|
|
self._istream.close()
|
|
|
|
def markSupported(self) -> bool:
|
|
return False
|
|
|
|
def mark(self, read_limit: int):
|
|
pass
|
|
|
|
def reset(self):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"CipherInputStream@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# CipherOutputStream
|
|
# ============================================================
|
|
|
|
class CipherOutputStream(Stub):
|
|
"""
|
|
javax.crypto.CipherOutputStream
|
|
A CipherOutputStream is composed of an OutputStream and a Cipher.
|
|
"""
|
|
def __init__(self, ostream, cipher: Cipher):
|
|
super().__init__()
|
|
self._ostream = ostream
|
|
self._cipher = cipher
|
|
|
|
def write(self, b: Any, off: int = None, le: int = None):
|
|
if isinstance(b, int):
|
|
data = bytes([b])
|
|
elif off is not None and le is not None:
|
|
data = bytes(b[off:off + le])
|
|
else:
|
|
data = bytes(b) if not isinstance(b, bytes) else b
|
|
encrypted = self._cipher.update(data)
|
|
if hasattr(self._ostream, 'write'):
|
|
self._ostream.write(encrypted)
|
|
|
|
def flush(self):
|
|
if hasattr(self._ostream, 'flush'):
|
|
self._ostream.flush()
|
|
|
|
def close(self):
|
|
final = self._cipher.doFinal()
|
|
if final and hasattr(self._ostream, 'write'):
|
|
self._ostream.write(final)
|
|
if hasattr(self._ostream, 'close'):
|
|
self._ostream.close()
|
|
|
|
def toString(self) -> str:
|
|
return f"CipherOutputStream@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF |