AES encryption of Image In Kotlin - kotlin

I am trying to encrypt and decrypt the image by AES in Kotlin
Key Generation Function-
override suspend fun key_genration(callback: Enc) {
val keygenerator = KeyGenerator.getInstance("AES")
keygenerator.init(128)
val secretKey: Key = keygenerator.generateKey()
val secretKey1 = secretKey.encoded
val result = Firebase.firestore.collection("profiles").document("YHMauLouORRtrYBV2h4dHJ5A0s72").update("key","$secretKey1")
}
Encryption Function -
override suspend fun encryption(imageView: ImageView, Key: ByteArray, name: String, uid: String) {
val bitmap = (imageView.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos) // bm is the bitmap object
val ba: ByteArray = baos.toByteArray()
val cipher = Cipher.getInstance("AES")
val keySpec = SecretKeySpec(Key, "AES")
Log.d("key11119","$keySpec")
cipher.init(Cipher.ENCRYPT_MODE, keySpec)
val txt = cipher.doFinal(ba)
Log.d("poott0","$txt")
val p = txt.toString(Charsets.ISO_8859_1)
Log.d("poott","$p")
// val encryptText = String(txt, Charset.defaultCharset())
val file = File.createTempFile("$name", ".txt")
file.writeText(p)
//val storageReference = FirebaseStorage.getInstance().getReference("image/$uid/$name")
val storageReference = FirebaseStorage.getInstance()
.getReference("/image/0XhL4jD4XCemk38rcRkIEjJMgjh2/Aadhar/")
storageReference.putFile(Uri.fromFile(file))
}
Decryption Function -
val img = view.findViewById<ImageView>(R.id.imageView2)
Firebase.firestore.collection("profiles").whereEqualTo("UID", "YHMauLouORRtrYBV2h4dHJ5A0s72").get()
.addOnSuccessListener {
val key = it.first().toObject(docretreving::class.java).key
Log.d("key111","$key")
Log.d("pooptt","Success")
val storageRef =
FirebaseStorage.getInstance().reference?.child("/image/0XhL4jD4XCemk38rcRkIEjJMgjh2/Aadhar/")
val localfile = File.createTempFile("temp",".txt")
storageRef.getFile(localfile)
.addOnSuccessListener {
Log.d("pooptt","Success")
val inputStream: InputStream = localfile.inputStream()
val inputString = inputStream.bufferedReader().use { it.readText() }
println(inputString)
Log.d("pooptt", inputString)
val key1 = "mxkLZmSFE1aKWzr6JyybjQ==".toByteArray()
Log.d("key111","$key1")
val keySpec = SecretKeySpec(key1, "AES")
val isro= inputString.toByteArray(Charsets.ISO_8859_1)
val cipher = Cipher.getInstance("AES")
cipher.init(Cipher.DECRYPT_MODE,keySpec)
var decryptedText : ByteArray = cipher.doFinal(isro)
Log.d("key110","$decryptedText")
val baos = ObjectInputStream(ByteArrayInputStream(decryptedText))
val bitmap = baos.readObject() as Bitmap
img.setImageBitmap(bitmap)
}
}
It says invalid Block size in decryption function , I am not sure if I am doing this correct. The key generating function the key and gives to encryption function[For now I was just testing with 1 key converted to base64 ]
Thanks in Advance

You should not put the ciphertext through a buffered reader, which handles text and may change binary data. Files and ciphertext both consist of bytes, you should treat them as such and not convert them to text. If you need text, use base 64.

Related

Decrypt KMS encrypted S3 objects from SES in Java

I am using an SES receipt rule to store KMS encrypted emails in S3 and looking at decrypting in a SpringBoot/Kotlin application. The only way I could achieve this using the AWS Java SDK v2 was decrypting myself using the BouncyCastle crypto lib. If I downgrade to AWS Java SDK v1 I can easily decrypt using AmazonS3EncryptionClient without worrying about the crypto operations but its deprecated.
What is the preferred way to read these KMS encrypted S3 objects from SES using the latest AWS Java SDK?
Below are my various attempts:
AWS SDKv1 - works perfectly but deprecated
val provider = KMSEncryptionMaterialsProvider(kmsArn)
val s3EncryptionClient = AmazonS3EncryptionClient.encryptionBuilder()
.withEncryptionMaterials(provider)
.withCryptoConfiguration(CryptoConfiguration()
.withCryptoMode(CryptoMode.AuthenticatedEncryption)
.withAwsKmsRegion(Region.getRegion(Regions.US_WEST_2)))
.build()
println(s3EncryptionClient.getObjectAsString(bucket, key))
AWS SDKv1 (V2) - fails on the EncryptionContext validation?
val provider = KMSEncryptionMaterialsProvider(kmsArn)
val s3EncryptionClient = AmazonS3EncryptionClientV2Builder.standard()
.withRegion(Regions.US_WEST_2)
.withCryptoConfiguration(CryptoConfigurationV2()
.withCryptoMode(CryptoMode.AuthenticatedEncryption)
.withAwsKmsRegion(com.amazonaws.regions.Region.getRegion(Regions.US_WEST_2)))
.withEncryptionMaterialsProvider(kmsProvider)
.build()
val result = s3EncryptionClient.getObject(bucket, key)
println(String(result.objectContent.readAllBytes()))
AWS SDKv2 + BouncyCastle - works perfectly but I have to do all the decryption myself
fun getAsDecryptedString(bucket: String, key: String): String {
Security.addProvider(BouncyCastleProvider())
val headObjectResponse = s3AsyncClient.headObject(
HeadObjectRequest.builder().bucket(bucket).key(key).build()
).get()
val metadata = headObjectResponse.metadata()
val kmsKeyBase64 = metadata["x-amz-key-v2"]
val iv = metadata["x-amz-iv"]
val algo = checkNotNull(metadata["x-amz-cek-alg"]) { "x-amz-cek-alg metadata is required" }
val encryptionContext = objectMapper.readValue(metadata["x-amz-matdesc"], typeRef)
val kmsKey = SdkBytes.fromByteArray(Base64.getDecoder().decode(kmsKeyBase64))
val kmsDecryptResult = kmsClient.decrypt(
DecryptRequest.builder()
.ciphertextBlob(kmsKey)
.encryptionContext(encryptionContext)
.build()
)
val request = GetObjectRequest.builder().bucket(bucket).key(key).build()
val getObjectResponse = s3AsyncClient.getObject(request, AsyncResponseTransformer.toBytes()).get()
val keyBytes = kmsDecryptResult.plaintext().asByteArray()
val bytesToDecrypt = getObjectResponse.asByteArray()
val ivBytes = Base64.getDecoder().decode(iv)
return decryptWithAES(keyBytes, bytesToDecrypt, ivBytes, algo)
}
private fun decryptWithAES(keyBytes: ByteArray, bytesToDecrypt: ByteArray, ivBytes: ByteArray, algo: String): String {
val secretKey = SecretKeySpec(keyBytes, "AES")
val iv = IvParameterSpec(ivBytes)
synchronized(Cipher::class.java) {
val cipher = Cipher.getInstance(algo, "BC")
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv)
val plainText = ByteArray(cipher.getOutputSize(bytesToDecrypt.size))
var ptLength = cipher.update(bytesToDecrypt, 0, bytesToDecrypt.size, plainText, 0)
ptLength += cipher.doFinal(plainText, ptLength)
val decryptedString = String(plainText)
return decryptedString.trim { it <= ' ' }
}
}

Verifying signature from .ps7 file (PKCS#7/CMS) in Kotlin

I have a file fileA.json.p7s and I'm trying to validate the detached signature using Bouncy Castle.
However, the code fails on verification and returns the error:
org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value
Does anyone know how to fix this error?
Here is my code:
fun verifySignature(): Boolean {
val signatureContent = File("src/test/resources/fileA.json.p7s").readBytes()
val cmsSignedData = CMSSignedData(
signatureContent
)
val certStore = cmsSignedData.certificates
val signers = cmsSignedData.signerInfos
val signerCollection = signers.signers
val iterator = signerCollection.iterator()
while (iterator.hasNext()){
val signer = iterator.next()
val certCollection = certStore.getMatches(signer.sid as Selector<X509CertificateHolder?>)
val certIt = certCollection.iterator()
val cert = certIt.next() as X509CertificateHolder
if (signer.verify(JcaSimpleSignerInfoVerifierBuilder().build(cert))) { // this is where the code fails
return true
}
}
return false
}

when calling Coinbase pro sandbox api, invalid: 401 Unauthorized. Text: "{"message":"invalid signature"}" Kotlin

What I wanted to do is call the Coinbase sandbox API to get all accounts for a profile.
I am following the official documentation https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getaccounts
But keep getting this error
Client request(https://api-public.sandbox.exchange.coinbase.com/accounts) invalid: 401 Unauthorized. Text: "{"message":"invalid signature"}"
Am I missing something?
suspend fun getTradingAccounts(): String {
val timestamp = getTimeStamp()
val response: String = client.get("https://api-public.sandbox.exchange.coinbase.com/accounts") {
headers {
append("Accept", "application/json")
append("Content-Type", "application/json")
append(
"cb-access-key",
"MY_KEY..."
)
append("cb-access-passphrase", "MY_PASSPHRASE....")
append("cb-access-sign", signMessage(
timestamp = timestamp,
method = "GET",
path = "https://api-public.sandbox.exchange.coinbase.com/accounts"
))
append("cb-access-timestamp", timestamp)
}
}
return response
}
private fun getTimeStamp(): String {
val time = LocalDateTime.now()
val zoneId = ZoneId.of("Europe/London")
val epoch = time.atZone(zoneId).toEpochSecond()
return epoch.toString()
}
#Throws(NoSuchAlgorithmException::class, InvalidKeyException::class)
private fun signMessage(timestamp: String, method: String, path: String): String {
val prehash = timestamp + method + path
val sha256_HMAC = Mac.getInstance("HmacSHA256")
val secretDecoded: ByteArray = Base64.getDecoder().decode("MY_API_KEY==")
val secret_key = SecretKeySpec(secretDecoded, "HmacSHA256")
sha256_HMAC.init(secret_key)
return Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(prehash.toByteArray()))
}
As I see your code for signing messages doesn't use request body JSON string when concatenating components for a message. Here is my version for the function that returns the same string as in NodeJS script for the same inputs:
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.util.*
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
fun main() {
val result = sign(
secret = "TVlfQVBJX0tFWQ==",
timestampMs = System.currentTimeMillis(),
method = "POST",
requestPath = "/orders",
request = Req(
price = "1.0",
size = "1.0",
side = "buy",
product_id = "BTC-USD",
)
)
println(result)
}
#OptIn(ExperimentalSerializationApi::class)
fun sign(timestampMs: Long, method: String, requestPath: String, request: Req, secret: String): String {
val accessTimestamp = timestampMs / 1000.0
val message = "%.3f".format(accessTimestamp) + method + requestPath + Json.encodeToString(request)
val sha256HMAC = Mac.getInstance("HmacSHA256")
val key: ByteArray = Base64.getDecoder().decode(secret)
sha256HMAC.init(SecretKeySpec(key, "HmacSHA256"))
return Base64.getEncoder().encodeToString(
sha256HMAC.doFinal(message.toByteArray())
)
}
#Serializable
data class Req(val price: String, val size: String, val side: String, val product_id: String)

How can I grab specific text from this html file? Using Jsoup functionality in Kotlin

Code:
import org.jsoup.Jsoup
fun main(){
val url = "https://www.google.com/maps/place/?q=place_id:"
//val placeID:String = "ChIJRVY_etDX3IARGYLVpoq7f68";
val placeID:String = "ChIJ1zoUGxYE9YgRL399jlxWp6Q";
val doc = Jsoup.connect(url+placeID).get()
val text = doc.html()
//println(text)
when (text)
{
is String -> println("yay");
}
//val pID: Collection<String>? = placeID as? String
//val here: Pair<Int, String>? = text.findLastAnyOf(placeID,0,false);
var tempLine:String = ""
tempLine = text.substringAfterLast(placeID)
val newLength = tempLine.length
var tempLine2 = tempLine.substringBefore("window.APP_FLAGS")
println(tempLine2)
}
Output.jpg
The text I want to specifically grab and return
I am working on a personal side project and I have hit a wall, where I cannot grab the busy time information from Google's page, this location is Trader Joes.

Kotlin: Unresolved reference: use,

I am trying to integrate a Dialogflow Agent with Pepper: https://developer.softbankrobotics.com/pepper-qisdk/lessons/integrating-chatbot-dialogflow
I followed all the steps until the Testing your agent in standalone section, where I have to add the following Kotlin code to the DialogflowSource class:
import com.google.auth.oauth2.ServiceAccountCredentials
import com.google.cloud.dialogflow.v2.*
import java.io.InputStream
class DialogflowDataSource constructor(credentialsStream : InputStream) {
private val credentials : ServiceAccountCredentials
= ServiceAccountCredentials.fromStream(credentialsStream)
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
SessionsClient.create(sessionsSettings).use { sessionsClient -> //Error: Unresolved reference for .use
val session = SessionName.of(credentials.projectId, sessionId)
val textInput = TextInput.newBuilder()
.setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput
.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
return response.queryResult.fulfillmentText
}
} //Error: A 'return' expression required in a function with a block body ('{...}')
}
I'm new to Kotlin, so I don't really know how to fix this. Any help would be appreciated!
First, why would you use use? It seems you meant to call apply instead. But in fact you could just write:
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
val sessionClient = SessionsClient.create(sessionsSettings)
val session = SessionName.of(credentials.projectId, sessionId)
val textInput =
TextInput.newBuilder().setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
return response.queryResult.fulfillmentText
}
But if you care using use (or apply), the lambda you provide to it should not directly make the outer function detectIntentTexts return. Instead, let your lambda return its result locally, and let detectIntentTexts return it:
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
return SessionsClient.create(sessionsSettings).apply { sessionsClient ->
val session = SessionName.of(credentials.projectId, sessionId)
val textInput = TextInput.newBuilder()
.setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput
.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
response.queryResult.fulfillmentText
}
}
}