mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-12-21 13:45:50 +00:00
complete preview tools for passport
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
import dev.inmo.micro_utils.crypto.SourceBytes
|
||||
import dev.inmo.tgbotapi.types.passport.credentials.EncryptedData
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
class AESDecryptor(key: SourceBytes, private val iv: ByteArray) : Decryptor {
|
||||
private val key = SecretKeySpec(key, "AES");
|
||||
|
||||
override fun decrypt(data: EncryptedData): SourceBytes {
|
||||
return Cipher.getInstance("AES/CBC/NOPADDING").run {
|
||||
init(Cipher.DECRYPT_MODE, key, IvParameterSpec(this@AESDecryptor.iv))
|
||||
val decryptedCredentials = doFinal(data)
|
||||
|
||||
val padding = decryptedCredentials.first()
|
||||
decryptedCredentials.copyOfRange(padding.toInt(), decryptedCredentials.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
import dev.inmo.micro_utils.crypto.decodeBase64
|
||||
import dev.inmo.tgbotapi.types.passport.credentials.DecryptedCredentials
|
||||
import dev.inmo.tgbotapi.types.passport.credentials.EncryptedCredentials
|
||||
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||
import java.security.*
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
private val regexToRemoveFromKey = Regex("(-----(BEGIN|END) ((?:.*? KEY)|CERTIFICATE)-----|[\\s])")
|
||||
|
||||
fun EncryptedCredentials.decryptWithPKCS8PrivateKey(privateKey: PrivateKey): DecryptedCredentials {
|
||||
val decrypted = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding").run {
|
||||
init(Cipher.DECRYPT_MODE, privateKey)
|
||||
doFinal(secret)
|
||||
}
|
||||
val dataDecryptor = (decrypted to hash).createDecryptor()
|
||||
val decryptedCredentials = dataDecryptor.decrypt(data).decodeToString()
|
||||
return nonstrictJsonFormat.decodeFromString(DecryptedCredentials.serializer(), decryptedCredentials)
|
||||
}
|
||||
|
||||
fun EncryptedCredentials.decryptWithPKCS8PrivateKey(key: String) = decryptWithPKCS8PrivateKey(
|
||||
KeyFactory.getInstance("RSA").generatePrivate(
|
||||
PKCS8EncodedKeySpec(key.replace(regexToRemoveFromKey, "").decodeBase64())
|
||||
)
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
import dev.inmo.micro_utils.crypto.SourceBytes
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.requests.DownloadFile
|
||||
import dev.inmo.tgbotapi.requests.get.GetFile
|
||||
import dev.inmo.tgbotapi.types.passport.credentials.*
|
||||
import dev.inmo.tgbotapi.types.passport.encrypted.PassportFile
|
||||
|
||||
fun EndDataCredentials.decryptData(
|
||||
bytes: EncryptedData
|
||||
): SourceBytes {
|
||||
return createDecryptor().decrypt(bytes)
|
||||
}
|
||||
|
||||
fun FileCredentials.decryptFile(
|
||||
fileBytes: ByteArray
|
||||
): SourceBytes {
|
||||
return createDecryptor().decrypt(fileBytes)
|
||||
}
|
||||
suspend fun FileCredentials.decryptFile(
|
||||
bot: TelegramBot,
|
||||
passportFile: PassportFile
|
||||
): SourceBytes {
|
||||
val pathedFile = bot.execute(GetFile(passportFile.fileId))
|
||||
val bytes = bot.execute(DownloadFile(pathedFile.filePath))
|
||||
return decryptFile(bytes)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
import dev.inmo.micro_utils.crypto.SourceBytes
|
||||
import dev.inmo.tgbotapi.types.passport.credentials.EndDataCredentials
|
||||
import java.security.MessageDigest
|
||||
|
||||
fun Pair<SourceBytes, SourceBytes>.createDecryptor(): Decryptor {
|
||||
val secretHash = MessageDigest.getInstance("SHA-512").digest(first + second)
|
||||
val key = secretHash.copyOf(32)
|
||||
val iv = secretHash.copyOfRange(32, 48)
|
||||
|
||||
return AESDecryptor(key, iv)
|
||||
}
|
||||
|
||||
fun EndDataCredentials.createDecryptor() = (secret to hash).createDecryptor()
|
||||
@@ -1,39 +0,0 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
import dev.inmo.micro_utils.crypto.decodeBase64
|
||||
import java.security.KeyFactory
|
||||
import java.security.interfaces.RSAPrivateKey
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import javax.crypto.Cipher
|
||||
|
||||
private val regexToRemoveFromKey = Regex("(-----(BEGIN|END) ((?:.*? KEY)|CERTIFICATE)-----|[\\s])")
|
||||
|
||||
/**
|
||||
* @param key PKCS8
|
||||
*/
|
||||
class PKCS8Decryptor (key: String): Decryptor {
|
||||
private val privateKey: RSAPrivateKey = KeyFactory.getInstance("RSA").generatePrivate(
|
||||
PKCS8EncodedKeySpec(key.replace(regexToRemoveFromKey, "").decodeBase64())
|
||||
) as RSAPrivateKey
|
||||
private val chunkSize: Int = privateKey.modulus.bitLength() / 8
|
||||
|
||||
override fun ByteArray.decrypt(): ByteArray {
|
||||
return Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING").run {
|
||||
init(Cipher.DECRYPT_MODE, privateKey)
|
||||
(0 until size step chunkSize).flatMap {
|
||||
val firstIndex = it
|
||||
val lastIndexExclusive = if (it + chunkSize > size) {
|
||||
size
|
||||
} else {
|
||||
it + chunkSize
|
||||
}
|
||||
doFinal(copyOfRange(firstIndex, lastIndexExclusive)).toList()
|
||||
}.toByteArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Decryptor(key: String) = PKCS8Decryptor(key)
|
||||
|
||||
inline fun <T> doWithDecryptor(decryptor: Decryptor, crossinline block: Decryptor.() -> T) = decryptor.run(block)
|
||||
inline fun <T> doWithDecryptor(key: String, crossinline block: Decryptor.() -> T) = doWithDecryptor(Decryptor(key), block)
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.inmo.tgbotapi.utils.passport
|
||||
|
||||
import dev.inmo.tgbotapi.types.passport.PassportData
|
||||
import dev.inmo.tgbotapi.types.passport.decrypted.SecureData
|
||||
import java.security.PrivateKey
|
||||
|
||||
inline fun <T> PassportData.doInDecryptionContextWithPKCS8Key(
|
||||
pkcs8Key: PrivateKey,
|
||||
expectedNonce: String? = null,
|
||||
crossinline block: SecureData.() -> T
|
||||
): T {
|
||||
val decryptedCredentials = credentials.decryptWithPKCS8PrivateKey(pkcs8Key)
|
||||
expectedNonce ?.let { require(expectedNonce == decryptedCredentials.nonce) }
|
||||
return decryptedCredentials.secureData.run(block)
|
||||
}
|
||||
Reference in New Issue
Block a user