Files
xiaozhi-user-uniappx/uni_modules/laoqianjunzi-crypto/utssdk/app-android/NativeCipherCore.kt
T

745 lines
27 KiB
Kotlin

package uts.sdk.modules.laoqianjunziCrypto
import android.util.Base64
import java.io.ByteArrayOutputStream
import java.nio.charset.StandardCharsets
import java.security.GeneralSecurityException
import java.security.KeyFactory
import java.security.KeyPairGenerator
import java.security.MessageDigest
import java.security.SecureRandom
import java.security.interfaces.RSAPrivateKey
import java.security.interfaces.RSAPublicKey
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher
import javax.crypto.Mac
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
data class NativeRsaBundle(val publicKey: String, val privateKey: String)
object NativeCipherCore {
private const val AES_BLOCK_SIZE = 16
private const val DES_BLOCK_SIZE = 8
private val secureRandom = SecureRandom()
fun digestHex(kind: String, plainText: String): String {
return try {
val digest = MessageDigest.getInstance(resolveDigestAlgorithm(kind))
toHex(digest.digest(plainText.toByteArray(StandardCharsets.UTF_8)))
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalStateException("摘要失败")
}
}
fun hmacHex(kind: String, secretText: String, plainText: String): String {
return try {
val mac = Mac.getInstance(resolveHmacAlgorithm(kind))
mac.init(SecretKeySpec(secretText.toByteArray(StandardCharsets.UTF_8), mac.algorithm))
toHex(mac.doFinal(plainText.toByteArray(StandardCharsets.UTF_8)))
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalStateException("HMAC失败")
}
}
fun encodeBase64(plainText: String): String {
return Base64.encodeToString(plainText.toByteArray(StandardCharsets.UTF_8), Base64.NO_WRAP)
}
fun decodeBase64(encodedText: String): String {
return try {
String(Base64.decode(encodedText, Base64.DEFAULT), StandardCharsets.UTF_8)
} catch (e: Exception) {
throw IllegalArgumentException("Base64无效")
}
}
fun encodeCodec(codec: String, plainText: String): String {
val bytes = plainText.toByteArray(StandardCharsets.UTF_8)
return when (codec.lowercase()) {
"utf8" -> plainText
"hex" -> toHex(bytes)
"base64" -> Base64.encodeToString(bytes, Base64.NO_WRAP)
"base64url" -> Base64.encodeToString(bytes, Base64.NO_WRAP)
.replace('+', '-')
.replace('/', '_')
.trimEnd('=')
"latin1" -> latin1FromBytes(bytes)
"utf16" -> utf16CodecFromBytes(bytes)
else -> throw IllegalArgumentException("不支持的编码类型")
}
}
fun decodeCodec(codec: String, encodedText: String): String {
return when (codec.lowercase()) {
"utf8" -> encodedText
"hex" -> String(fromHex(encodedText), StandardCharsets.UTF_8)
"base64" -> decodeBase64(encodedText)
"base64url" -> {
var normalized = encodedText.replace('-', '+').replace('_', '/')
while (normalized.length % 4 != 0) {
normalized += '='
}
decodeBase64(normalized)
}
"latin1" -> String(bytesFromLatin1(encodedText), StandardCharsets.UTF_8)
"utf16" -> String(bytesFromUtf16Codec(encodedText), StandardCharsets.UTF_8)
else -> throw IllegalArgumentException("不支持的编码类型")
}
}
fun aesEncryptText(
secretText: String,
plainText: String,
mode: String,
padding: String,
ivText: String?,
keyLength: Int?
): String {
val cipherBytes = aesEncryptBytes(
secretText.toByteArray(StandardCharsets.UTF_8),
plainText.toByteArray(StandardCharsets.UTF_8),
mode,
padding,
ivText?.toByteArray(StandardCharsets.UTF_8),
keyLength
)
return Base64.encodeToString(cipherBytes, Base64.NO_WRAP)
}
fun aesDecryptText(
secretText: String,
cipherText: String,
mode: String,
padding: String,
ivText: String?,
keyLength: Int?
): String {
val cipherBytes = try {
Base64.decode(cipherText, Base64.DEFAULT)
} catch (e: Exception) {
throw IllegalArgumentException("密文Base64无效")
}
val plainBytes = aesDecryptBytes(
secretText.toByteArray(StandardCharsets.UTF_8),
cipherBytes,
mode,
padding,
ivText?.toByteArray(StandardCharsets.UTF_8),
keyLength
)
return String(plainBytes, StandardCharsets.UTF_8)
}
fun aesEncryptBytes(
secretBytes: ByteArray,
plainBytes: ByteArray,
mode: String,
padding: String,
ivBytes: ByteArray?,
keyLength: Int?
): ByteArray {
return cryptAes(true, secretBytes, plainBytes, mode, padding, ivBytes, keyLength)
}
fun aesDecryptBytes(
secretBytes: ByteArray,
cipherBytes: ByteArray,
mode: String,
padding: String,
ivBytes: ByteArray?,
keyLength: Int?
): ByteArray {
return cryptAes(false, secretBytes, cipherBytes, mode, padding, ivBytes, keyLength)
}
fun tripleDesEncryptText(secretText: String, plainText: String, mode: String, ivText: String?): String {
val encrypted = cryptTripleDes(
true,
secretText.toByteArray(StandardCharsets.UTF_8),
plainText.toByteArray(StandardCharsets.UTF_8),
mode,
ivText?.toByteArray(StandardCharsets.UTF_8)
)
return Base64.encodeToString(encrypted, Base64.NO_WRAP)
}
fun tripleDesDecryptText(secretText: String, cipherText: String, mode: String, ivText: String?): String {
val cipherBytes = try {
Base64.decode(cipherText, Base64.DEFAULT)
} catch (e: Exception) {
throw IllegalArgumentException("密文Base64无效")
}
val decrypted = cryptTripleDes(
false,
secretText.toByteArray(StandardCharsets.UTF_8),
cipherBytes,
mode,
ivText?.toByteArray(StandardCharsets.UTF_8)
)
return String(decrypted, StandardCharsets.UTF_8)
}
fun desEncryptText(secretText: String, plainText: String, mode: String, padding: String, ivText: String?): String {
val encrypted = cryptDes(
true,
secretText.toByteArray(StandardCharsets.UTF_8),
plainText.toByteArray(StandardCharsets.UTF_8),
mode,
padding,
ivText?.toByteArray(StandardCharsets.UTF_8)
)
return Base64.encodeToString(encrypted, Base64.NO_WRAP)
}
fun desDecryptText(secretText: String, cipherText: String, mode: String, padding: String, ivText: String?): String {
val cipherBytes = try {
Base64.decode(cipherText, Base64.DEFAULT)
} catch (e: Exception) {
throw IllegalArgumentException("密文Base64无效")
}
val decrypted = cryptDes(
false,
secretText.toByteArray(StandardCharsets.UTF_8),
cipherBytes,
mode,
padding,
ivText?.toByteArray(StandardCharsets.UTF_8)
)
return String(decrypted, StandardCharsets.UTF_8)
}
fun rc4EncryptToHex(secretText: String, plainText: String): String {
return toHex(rc4(secretText.toByteArray(StandardCharsets.UTF_8), plainText.toByteArray(StandardCharsets.UTF_8)))
}
fun rc4DecryptFromHex(secretText: String, cipherHexText: String): String {
val plainBytes = rc4(secretText.toByteArray(StandardCharsets.UTF_8), fromHex(cipherHexText))
return String(plainBytes, StandardCharsets.UTF_8)
}
fun createRsaBundle(keySize: Int): NativeRsaBundle {
return try {
val generator = KeyPairGenerator.getInstance("RSA")
generator.initialize(keySize)
val pair = generator.generateKeyPair()
val publicPem = toPem("PUBLIC KEY", pair.public.encoded)
val privatePem = toPem("PRIVATE KEY", pair.private.encoded)
NativeRsaBundle(publicPem, privatePem)
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalStateException("RSA生成失败")
}
}
fun rsaEncrypt(publicKey: String, plainText: String, outputKind: String?): String {
return try {
val rsaKey = parsePublicKey(publicKey)
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, rsaKey)
val encrypted = rsaProcess(cipher, plainText.toByteArray(StandardCharsets.UTF_8), rsaEncryptChunkSize(rsaKey), "RSA加密失败")
if (isHexOutput(outputKind)) toHex(encrypted) else Base64.encodeToString(encrypted, Base64.NO_WRAP)
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalStateException("RSA加密失败")
}
}
fun rsaDecrypt(privateKey: String, cipherText: String, outputKind: String?): String {
return try {
val rsaKey = parsePrivateKey(privateKey)
val cipherBytes = if (isHexOutput(outputKind)) {
fromHex(cipherText)
} else {
try {
Base64.decode(cipherText, Base64.DEFAULT)
} catch (e: Exception) {
throw IllegalArgumentException("RSA密文无效")
}
}
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.DECRYPT_MODE, rsaKey)
val decrypted = rsaProcess(cipher, cipherBytes, rsaDecryptChunkSize(rsaKey), "RSA解密失败")
String(decrypted, StandardCharsets.UTF_8)
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalStateException("RSA解密失败")
}
}
private fun cryptAes(
encrypt: Boolean,
secretBytes: ByteArray,
inputBytes: ByteArray,
mode: String,
padding: String,
ivBytes: ByteArray?,
keyLength: Int?
): ByteArray {
try {
val normalizedMode = resolveAesMode(mode)
val normalizedPadding = resolvePadding(padding)
val key = SecretKeySpec(normalizeAesKey(secretBytes, keyLength), "AES")
val data = if (encrypt) padBytes(inputBytes, AES_BLOCK_SIZE, normalizedPadding) else inputBytes
if (!encrypt && data.isEmpty()) {
return ByteArray(0)
}
val cipher = Cipher.getInstance("AES/$normalizedMode/NoPadding")
initCipher(cipher, encrypt, key, normalizedMode, normalizeIv(ivBytes, AES_BLOCK_SIZE, normalizedMode))
val output = cipher.doFinal(data)
return if (encrypt) output else unpadBytes(output, AES_BLOCK_SIZE, normalizedPadding)
} catch (e: IllegalArgumentException) {
throw e
} catch (e: GeneralSecurityException) {
throw IllegalStateException(if (encrypt) "AES加密失败" else "AES解密失败")
}
}
private fun cryptTripleDes(
encrypt: Boolean,
secretBytes: ByteArray,
inputBytes: ByteArray,
mode: String,
ivBytes: ByteArray?
): ByteArray {
try {
val normalizedMode = resolveTripleDesMode(mode)
val key = SecretKeySpec(normalizeTripleDesKey(secretBytes), "DESede")
val data = if (encrypt) padBytes(inputBytes, DES_BLOCK_SIZE, "PKCS7") else inputBytes
val cipher = Cipher.getInstance("DESede/$normalizedMode/NoPadding")
initCipher(cipher, encrypt, key, normalizedMode, normalizeIv(ivBytes, DES_BLOCK_SIZE, normalizedMode))
val output = cipher.doFinal(data)
return if (encrypt) output else unpadBytes(output, DES_BLOCK_SIZE, "PKCS7")
} catch (e: IllegalArgumentException) {
throw e
} catch (e: GeneralSecurityException) {
throw IllegalStateException(if (encrypt) "3DES加密失败" else "3DES解密失败")
}
}
private fun cryptDes(
encrypt: Boolean,
secretBytes: ByteArray,
inputBytes: ByteArray,
mode: String,
padding: String,
ivBytes: ByteArray?
): ByteArray {
try {
val normalizedMode = resolveDesMode(mode)
val normalizedPadding = resolvePadding(padding)
val key = SecretKeySpec(normalizeDesKey(secretBytes), "DES")
val data = if (encrypt) padBytes(inputBytes, DES_BLOCK_SIZE, normalizedPadding) else inputBytes
if (!encrypt && data.isEmpty()) {
return ByteArray(0)
}
val cipher = Cipher.getInstance("DES/$normalizedMode/NoPadding")
initCipher(cipher, encrypt, key, normalizedMode, normalizeIv(ivBytes, DES_BLOCK_SIZE, normalizedMode))
val output = cipher.doFinal(data)
return if (encrypt) output else unpadBytes(output, DES_BLOCK_SIZE, normalizedPadding)
} catch (e: IllegalArgumentException) {
throw e
} catch (e: GeneralSecurityException) {
throw IllegalStateException(if (encrypt) "DES加密失败" else "DES解密失败")
}
}
private fun initCipher(cipher: Cipher, encrypt: Boolean, key: SecretKeySpec, mode: String, ivBytes: ByteArray?) {
if (mode == "ECB") {
cipher.init(if (encrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, key)
} else {
val actualIv = ivBytes ?: throw IllegalArgumentException("IV不能为空")
cipher.init(if (encrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, key, IvParameterSpec(actualIv))
}
}
private fun resolveDigestAlgorithm(kind: String): String {
return when (kind.lowercase()) {
"md5" -> "MD5"
"sha1" -> "SHA-1"
"sha256" -> "SHA-256"
"sha512" -> "SHA-512"
else -> throw IllegalArgumentException("不支持的摘要算法")
}
}
private fun resolveHmacAlgorithm(kind: String): String {
return when (kind.lowercase()) {
"sha1" -> "HmacSHA1"
"sha256" -> "HmacSHA256"
"sha512" -> "HmacSHA512"
else -> throw IllegalArgumentException("不支持的HMAC算法")
}
}
private fun resolveAesMode(mode: String): String {
return when (mode.uppercase()) {
"ECB", "CBC", "CFB", "CTR", "OFB" -> mode.uppercase()
// CTRGladman 在 Android 端按标准 CTR 变换兼容映射处理。
"CTRGLADMAN" -> "CTR"
else -> throw IllegalArgumentException("不支持的AES模式")
}
}
private fun resolveTripleDesMode(mode: String): String {
return when (mode.uppercase()) {
"ECB", "CBC" -> mode.uppercase()
else -> throw IllegalArgumentException("不支持的3DES模式")
}
}
private fun resolveDesMode(mode: String): String {
return when (mode.uppercase()) {
"ECB", "CBC", "CFB", "CTR", "OFB" -> mode.uppercase()
"CTRGLADMAN" -> "CTR"
else -> throw IllegalArgumentException("不支持的DES模式")
}
}
private fun resolvePadding(padding: String): String {
return when (padding.uppercase()) {
"PKCS7", "ANSI_X923", "ISO_10126", "ISO_97971", "NONE", "ZERO" -> padding.uppercase()
else -> throw IllegalArgumentException("不支持的填充")
}
}
private fun normalizeAesKey(secretBytes: ByteArray, keyLength: Int?): ByteArray {
val keySize = when (keyLength) {
null -> inferAesKeySize(secretBytes.size)
128, 192, 256 -> keyLength / 8
else -> throw IllegalArgumentException("AES密钥长度无效")
}
return fitBytes(secretBytes, keySize)
}
private fun inferAesKeySize(size: Int): Int {
return when {
size <= 16 -> 16
size <= 24 -> 24
size <= 32 -> 32
else -> throw IllegalArgumentException("AES密钥长度无效")
}
}
private fun normalizeTripleDesKey(secretBytes: ByteArray): ByteArray {
val source = fitBytes(secretBytes, 24)
if (secretBytes.size <= 16) {
System.arraycopy(source, 0, source, 16, 8)
}
return source
}
private fun normalizeDesKey(secretBytes: ByteArray): ByteArray {
if (secretBytes.isEmpty()) {
throw IllegalArgumentException("密钥不能为空")
}
return fitBytes(secretBytes, 8)
}
private fun normalizeIv(ivBytes: ByteArray?, expectedSize: Int, mode: String): ByteArray? {
if (mode == "ECB") return null
val bytes = ivBytes ?: return null
return fitBytes(bytes, expectedSize)
}
private fun fitBytes(source: ByteArray, targetSize: Int): ByteArray {
val output = ByteArray(targetSize)
val copySize = minOf(source.size, targetSize)
System.arraycopy(source, 0, output, 0, copySize)
return output
}
private fun padBytes(input: ByteArray, blockSize: Int, padding: String): ByteArray {
if (padding == "NONE") {
if (input.size % blockSize != 0) {
throw IllegalArgumentException("数据长度不是块大小整数倍")
}
return input
}
val padSize = blockSize - (input.size % blockSize).let { if (it == 0) blockSize else it }
val actualPadSize = if (padSize == 0) blockSize else padSize
val output = ByteArray(input.size + actualPadSize)
System.arraycopy(input, 0, output, 0, input.size)
when (padding) {
"PKCS7" -> fillPad(output, input.size, actualPadSize, actualPadSize.toByte())
"ANSI_X923" -> output[output.lastIndex] = actualPadSize.toByte()
"ISO_10126" -> {
val randomBytes = ByteArray(actualPadSize - 1)
if (randomBytes.isNotEmpty()) {
secureRandom.nextBytes(randomBytes)
System.arraycopy(randomBytes, 0, output, input.size, randomBytes.size)
}
output[output.lastIndex] = actualPadSize.toByte()
}
"ISO_97971" -> {
output[input.size] = 0x80.toByte()
}
"ZERO" -> {
}
else -> throw IllegalArgumentException("不支持的填充")
}
return output
}
private fun fillPad(output: ByteArray, start: Int, count: Int, value: Byte) {
for (i in start until start + count) {
output[i] = value
}
}
private fun unpadBytes(input: ByteArray, blockSize: Int, padding: String): ByteArray {
if (padding == "NONE") {
return input
}
if (input.isEmpty() || input.size % blockSize != 0) {
throw IllegalArgumentException("密文长度无效")
}
val dataLength = when (padding) {
"PKCS7" -> {
val padSize = input.last().toInt() and 0xFF
validatePadSize(padSize, blockSize)
for (i in input.size - padSize until input.size) {
if ((input[i].toInt() and 0xFF) != padSize) {
throw IllegalArgumentException("填充无效")
}
}
input.size - padSize
}
"ANSI_X923" -> {
val padSize = input.last().toInt() and 0xFF
validatePadSize(padSize, blockSize)
for (i in input.size - padSize until input.lastIndex) {
if (input[i].toInt() != 0) {
throw IllegalArgumentException("填充无效")
}
}
input.size - padSize
}
"ISO_10126" -> {
val padSize = input.last().toInt() and 0xFF
validatePadSize(padSize, blockSize)
input.size - padSize
}
"ISO_97971" -> {
var index = input.lastIndex
while (index >= 0 && input[index].toInt() == 0) {
index -= 1
}
if (index < 0 || input[index] != 0x80.toByte()) {
throw IllegalArgumentException("填充无效")
}
index
}
"ZERO" -> {
var index = input.size
while (index > 0 && input[index - 1].toInt() == 0) {
index -= 1
}
index
}
else -> throw IllegalArgumentException("不支持的填充")
}
return input.copyOf(dataLength)
}
private fun validatePadSize(padSize: Int, blockSize: Int) {
if (padSize <= 0 || padSize > blockSize) {
throw IllegalArgumentException("填充无效")
}
}
private fun rc4(secretBytes: ByteArray, inputBytes: ByteArray): ByteArray {
if (secretBytes.isEmpty()) {
throw IllegalArgumentException("RC4密钥不能为空")
}
val s = IntArray(256) { it }
var j = 0
for (i in 0 until 256) {
j = (j + s[i] + (secretBytes[i % secretBytes.size].toInt() and 0xFF)) and 0xFF
val tmp = s[i]
s[i] = s[j]
s[j] = tmp
}
val output = ByteArray(inputBytes.size)
var i = 0
j = 0
for (index in inputBytes.indices) {
i = (i + 1) and 0xFF
j = (j + s[i]) and 0xFF
val tmp = s[i]
s[i] = s[j]
s[j] = tmp
val keyByte = s[(s[i] + s[j]) and 0xFF]
output[index] = (inputBytes[index].toInt() xor keyByte).toByte()
}
return output
}
private fun parsePublicKey(publicKey: String): RSAPublicKey {
try {
val keyBytes = decodePem(publicKey, "PUBLIC KEY")
val keySpec = X509EncodedKeySpec(keyBytes)
return KeyFactory.getInstance("RSA").generatePublic(keySpec) as RSAPublicKey
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalArgumentException("公钥无效")
}
}
private fun parsePrivateKey(privateKey: String): RSAPrivateKey {
try {
val keyBytes = decodePem(privateKey, "PRIVATE KEY")
val keySpec = PKCS8EncodedKeySpec(keyBytes)
return KeyFactory.getInstance("RSA").generatePrivate(keySpec) as RSAPrivateKey
} catch (e: IllegalArgumentException) {
throw e
} catch (e: Exception) {
throw IllegalArgumentException("私钥无效")
}
}
private fun decodePem(pemText: String, label: String): ByteArray {
val header = "-----BEGIN $label-----"
val footer = "-----END $label-----"
val trimmed = pemText.trim()
if (!trimmed.startsWith(header) || !trimmed.endsWith(footer)) {
throw IllegalArgumentException("PEM格式无效")
}
val content = trimmed
.removePrefix(header)
.removeSuffix(footer)
.replace("\\s".toRegex(), "")
return try {
Base64.decode(content, Base64.DEFAULT)
} catch (e: Exception) {
throw IllegalArgumentException("PEM内容无效")
}
}
private fun toPem(label: String, keyBytes: ByteArray): String {
val base64 = Base64.encodeToString(keyBytes, Base64.NO_WRAP)
val builder = StringBuilder()
builder.append("-----BEGIN ").append(label).append("-----\n")
var index = 0
while (index < base64.length) {
val end = minOf(index + 64, base64.length)
builder.append(base64, index, end).append('\n')
index = end
}
builder.append("-----END ").append(label).append("-----")
return builder.toString()
}
private fun rsaEncryptChunkSize(key: RSAPublicKey): Int {
return (key.modulus.bitLength() + 7) / 8 - 11
}
private fun rsaDecryptChunkSize(key: RSAPrivateKey): Int {
return (key.modulus.bitLength() + 7) / 8
}
private fun rsaProcess(cipher: Cipher, input: ByteArray, chunkSize: Int, failureMessage: String): ByteArray {
if (chunkSize <= 0) {
throw IllegalArgumentException("RSA密钥无效")
}
val output = ByteArrayOutputStream()
var offset = 0
try {
while (offset < input.size) {
val size = minOf(chunkSize, input.size - offset)
output.write(cipher.doFinal(input, offset, size))
offset += size
}
return output.toByteArray()
} catch (e: Exception) {
throw IllegalStateException(failureMessage)
} finally {
output.close()
}
}
private fun isHexOutput(outputKind: String?): Boolean {
return outputKind?.lowercase() == "hex"
}
private fun latin1FromBytes(bytes: ByteArray): String {
val chars = CharArray(bytes.size)
for (i in bytes.indices) {
chars[i] = (bytes[i].toInt() and 0xFF).toChar()
}
return String(chars)
}
private fun bytesFromLatin1(text: String): ByteArray {
val output = ByteArray(text.length)
for (i in text.indices) {
output[i] = (text[i].code and 0xFF).toByte()
}
return output
}
private fun utf16CodecFromBytes(bytes: ByteArray): String {
if (bytes.isEmpty()) {
return ""
}
val chars = CharArray((bytes.size + 1) / 2)
var byteIndex = 0
var charIndex = 0
while (byteIndex < bytes.size) {
val high = bytes[byteIndex].toInt() and 0xFF
val low = if (byteIndex + 1 < bytes.size) bytes[byteIndex + 1].toInt() and 0xFF else 0
chars[charIndex] = ((high shl 8) or low).toChar()
byteIndex += 2
charIndex += 1
}
return String(chars)
}
private fun bytesFromUtf16Codec(text: String): ByteArray {
val output = ByteArray(text.length * 2)
var index = 0
for (charValue in text) {
val code = charValue.code
output[index] = ((code ushr 8) and 0xFF).toByte()
output[index + 1] = (code and 0xFF).toByte()
index += 2
}
return output
}
private fun toHex(bytes: ByteArray): String {
val chars = CharArray(bytes.size * 2)
val digits = "0123456789abcdef"
for (i in bytes.indices) {
val value = bytes[i].toInt() and 0xFF
chars[i * 2] = digits[value ushr 4]
chars[i * 2 + 1] = digits[value and 0x0F]
}
return String(chars)
}
private fun fromHex(hexText: String): ByteArray {
val normalized = hexText.trim()
if (normalized.length % 2 != 0) {
throw IllegalArgumentException("Hex无效")
}
val output = ByteArray(normalized.length / 2)
for (i in output.indices) {
val start = i * 2
val value = normalized.substring(start, start + 2).toIntOrNull(16)
?: throw IllegalArgumentException("Hex无效")
output[i] = value.toByte()
}
return output
}
}