Verifying signature from .ps7 file (PKCS#7/CMS) in Kotlin - 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
}

Related

How to test a service function in kotlin which uses a late init Id?

I am new to testing in kotlin and I was wondering how I can test this function:
this is my SegmentService file:
fun createSegmentFromUserIds(userIds: List<String>, name:String, appId: String): Segmentation {
val filter = createUserIdFilter(userIds)
val createSegmentRequest = CreateSegmentRequest(
name = name, attribute = filter, type = SegmentType.STATIC
)
val segmentation = segmentMetaService.saveSegmentInfo(createSegmentRequest, appId)
querySegmentService.runUpdateQuery(users = userIds, appId = appId, segmentId = segmentation.id)
return segmentation
}
this is the saveSegmentInfo function:
fun saveSegmentInfo(createSegmentFilter: CreateSegmentRequest, appId: String): Segmentation {
val segmentInfo = segmentationRepository.save(createSegmentFilter.let {
Segmentation(
attribute = it.attribute, name = it.name, appId = appId, type = it.type
)
})
logger.info("Segment info saved with id: ${segmentInfo.id}, name: ${segmentInfo.name}")
return segmentInfo
}
and this is the Segmentation Document
#Document(Segmentation.COLLECTION_NAME)
class Segmentation(
#Field(ATTRIBUTE)
val attribute: Filter,
#Field(NAME)
val name: String,
#Indexed
#Field(APP_ID)
val appId: String,
#Field(STATUS)
var status: SegmentStatus = SegmentStatus.CREATED,
#Field(TYPE)
var type: SegmentType = SegmentType.STATIC,
#Field(USER_COUNT)
var userCount: Long? = null,
) {
#Id
lateinit var id: String
#Field(CREATION_DATE)
var creationDate: Date = Date()
}
I have written this test for it:
class SegmentServiceTest {
private val segmentMetaService = mock(SegmentMetaService::class.java)
private val querySegmentService = mock(QuerySegmentService::class.java)
private val converterService = mock(ConverterService::class.java)
private val userAttributeService = mock(UserAttributeService::class.java)
private val segmentConsumerUserInfoProducer = mock(SegmentConsumerUsersInfoProducer::class.java)
private val segmentationRepository = mock(SegmentationRepository::class.java)
#Test
fun `createSegmentFromUserIds should create a new segment`() {
val segmentService = SegmentService(
segmentMetaService = segmentMetaService,
querySegmentService = querySegmentService,
converterService = converterService,
userAttributeService = userAttributeService,
segmentConsumerUserInfoProducer = segmentConsumerUserInfoProducer
)
val userIds = listOf("user-1", "user-2", "user-3")
val filter = AndFilter(
operations = listOf(
AndFilter(
operations = listOf(
StringListContainsFilter(
field = "userId", operationType = StringQueryOperationType.IN, values = userIds
)
)
)
)
)
val createSegmentRequest = CreateSegmentRequest(
name = "segment-name", attribute = filter, type = SegmentType.STATIC
)
val segment = Segmentation(attribute = filter, name = "segment-name", type = SegmentType.STATIC, appId = "app-id" )
`when`(segmentationRepository.save(any())).thenReturn(segment)
`when`(segmentMetaService.saveSegmentInfo(createSegmentRequest, "app-id")).thenReturn(segment)
val createdSegment = segmentService.createSegmentFromUserIds(userIds = userIds, name = "segment-name", appId = "app-id")
assertEquals(segment, createdSegment)
}
}
but I am facing this error:
kotlin.UninitializedPropertyAccessException: lateinit property id has not been initialized
So what am I doing wrong here?
How can I initialize the Id? or should I refactor my code so for it to become testable?
I think you are mocking / providing the answers to the wrong calls.
you mock segmentationRepository.save(..) but this call won't ever be made since that call is inside segmentMetaService.saveSegmentInfo(...) which is mocked so the real code is not called.
when you call segmentService.createSegmentFromUserIds(..), my guess (stack trace would be useful on the error, BTW), is that this method proceeds passed the invocation of segmentMetaService.saveSegmentInfo(...) but in the next line you call querySegmentService.runUpdateQuery(users = userIds, appId = appId, segmentId = segmentation.id) which is accessing the uninitialised id.
The fix will be to set the segment.id when you set up the object for the answer to segmentMetaService.saveSegmentInfo(..)

Kafka Exception: The group member needs to have a valid member id before actually entering a consumer group

I have this consumer that appears to be connected to the kafka topic but after seeing the logs I'm seeing that the consumer Join group failed with org.apache.kafka.common.errors.MemberIdRequiredException: The group member needs to have a valid member id before actually entering a consumer group. I've tried looking at a few other setups online and I don't see anyone explicitly setting a member ID. I don't see this exception thrown locally so I'm hoping that maybe I just need to do some fine-tuning on the consumer configurations but I'm not sure what needs to be changed.
Kafka Consumer
#KafkaListener(
topics = ["my.topic"],
groupId ="kafka-consumer-group"
)
fun consume(consumerRecord: ConsumerRecord<String, Record>, ack: Acknowledgment) {
val value = consumerRecord.value()
val eventKey = consumerRecord.key()
val productNotificationEvent = buildProductNotificationEvent(value)
val consumerIdsByEventKey = eventKey.let { favoritesRepository.getConsumerIdsByEntityId(it) }
ack.acknowledge()
}
Kafka Consumer Config
#EnableKafka
#Configuration
class KafkaConsumerConfig(
#Value("\${KAFKA_SERVER}")
private val kafkaServer: String,
#Value("\${KAFKA_SASL_USERNAME}")
private val userName: String,
#Value("\${KAFKA_SASL_PASSWORD}")
private val password: String,
#Value("\${KAFKA_SCHEMA_REGISTRY_URL}")
private val schemaRegistryUrl: String,
#Value("\${KAFKA_SCHEMA_REGISTRY_USER_INFO}")
private val schemaRegistryUserInfo: String,
#Value("\${KAFKA_CONSUMER_MAX_POLL_IN_MS}")
private val maxPollIntervalMsConfig: Int,
#Value("\${KAFKA_CONSUMER_MAX_POLL_RECORDS}")
private val maxPollRecords: Int
) {
#Bean
fun consumerFactory(): ConsumerFactory<String?, Any?> {
val props: MutableMap<String, Any> = mutableMapOf()
props[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = kafkaServer
props[ConsumerConfig.GROUP_ID_CONFIG] = KAFKA_CONSUMER_GROUP_ID
props[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java
props[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = KafkaAvroDeserializer::class.java
props[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "earliest"
props[ConsumerConfig.MAX_POLL_RECORDS_CONFIG] = maxPollRecords
props[ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG] = maxPollIntervalMsConfig
props[CommonClientConfigs.SECURITY_PROTOCOL_CONFIG] = "SASL_SSL"
props[SaslConfigs.SASL_MECHANISM] = "PLAIN"
val module = "org.apache.kafka.common.security.plain.PlainLoginModule"
val jaasConfig = String.format(
"%s required username=\"%s\" password=\"%s\";",
module,
userName,
password
)
props[SaslConfigs.SASL_JAAS_CONFIG] = jaasConfig
props[KafkaAvroDeserializerConfig.VALUE_SUBJECT_NAME_STRATEGY] = TopicRecordNameStrategy::class.java
props[KafkaAvroDeserializerConfig.SCHEMA_REGISTRY_URL_CONFIG] = schemaRegistryUrl
props[KafkaAvroDeserializerConfig.BASIC_AUTH_CREDENTIALS_SOURCE] = "USER_INFO"
props[KafkaAvroDeserializerConfig.USER_INFO_CONFIG] = schemaRegistryUserInfo
return DefaultKafkaConsumerFactory(props)
}
#Bean
fun kafkaListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory<String, Any>? {
val factory = ConcurrentKafkaListenerContainerFactory<String, Any>()
factory.consumerFactory = consumerFactory()
factory.containerProperties.ackMode = ContainerProperties.AckMode.MANUAL_IMMEDIATE
factory.containerProperties.isSyncCommits = true
return factory
}
companion object {
private const val KAFKA_CONSUMER_GROUP_ID = "kafka-consumer-group"
}
}

AES encryption of Image In 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.

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
}
}
}

Why is the variable dowloadUrl returning null in the saveProfile method?

The following code shows the firebase storage upload task which I am using to get the variable downloadUrl, downloadUrl isn't null as it prints in the log but when I call the function saveProfile it returns null, why?
var downloadUrl: String? = null
fun upload(bytes: ByteArray) {
val storageReference = FirebaseStorage.getInstance().reference
.child(
"images/users/${FirebaseAuth.getInstance().currentUser!!.uid}/profile_image"
)
val metadata = StorageMetadata.Builder()
.setContentType("image/jpg")
.setContentLanguage("en")
.build()
storageReference.putBytes(bytes, metadata).addOnSuccessListener {
model.listener!!.progressBarGone()
model.listener!!.toast("Uploaded Successfully")
val urlTask = it.storage.downloadUrl
while (!urlTask.isSuccessful);
this.downloadUrl = urlTask.result.toString()
Log.d("Upload", "DownloadUrl $downloadUrl")
And this is the saveProfile function.
fun saveProfile() {
val user = User()
if (model.name.isNullOrEmpty() || model.phone.isNullOrEmpty()) {
model.listener!!.toast("Fields cannot be empty")
return
}
if (downloadUrl.isNullorEmpty()) {
log.d(TAG, "URL empty")
}
user.name = model.name
user.phone = model.phone
user.profile_image = downloadUrl
When you call
this.downloadUrl = urlTask.result.toString()
You assign downloadUrl to the object that is bound to the lambda you pass to addOnSuccessListener, not the global downloadUrl. For quick fix, I'd suggest you renaming global downloadUrl to some other name that wouldn't be shadowed.