Fix decryption function

This commit is contained in:
2020-07-05 18:16:37 +02:00
parent b1b4ad3030
commit 576e16a2fc
10 changed files with 128 additions and 43 deletions

View File

@@ -3,8 +3,6 @@ package com.github.mondei1.offpass
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.github.mondei1.offpass.entities.Compression
import com.github.mondei1.offpass.entities.CompressionHelper
import kotlinx.android.synthetic.main.activity_create.*
class CreateActivity : AppCompatActivity() {
@@ -18,13 +16,16 @@ class CreateActivity : AppCompatActivity() {
fragment_title = TextInput.newInstance("Title", "ENTER TITLE", "30dp")
fragment_username = TextInput.newInstance("Username", "ENTER USERNAME", "30dp")
supportFragmentManager.beginTransaction()
.replace(R.id.title, fragment_title!!)
.replace(R.id.title_box, fragment_title!!)
.replace(R.id.username, fragment_username!!)
.commit()
this.schema = QRSchema(this)
this.schema!!.decrypted_raw = "%JtuB4O9M42%Gitea|Nicolas|542superGoOD_pW&|klier.nicolas@protonmail.com|\$ul|(\$vb)\$O4|()What's your favorite series%Rick and morty|(2fa)otpauth://totp/OffPass%20Test?secret=d34gfkki5dkd5knifysrpgndd5xb2c7eddwki7ya4pvoisfa5c3ko5pv&issuer=Nicolas%20Klier"
this.schema!!.parse(this)
//this.schema = QRSchema(this)
//this.schema!!.decrypted_raw = "%JtuB4O9M42%Gitea|Nicolas|542superGoOD_pW&|klier.nicolas@protonmail.com|\$ul|(\$vb)\$O4|()What's your favorite series%Rick and morty|(2fa)otpauth://totp/OffPass%20Test?secret=d34gfkki5dkd5knifysrpgndd5xb2c7eddwki7ya4pvoisfa5c3ko5pv&issuer=Nicolas%20Klier"
//this.schema!!.parse(this)
//this.schema!!.build(arrayOf("website_url", "2fa", "What's your favorite series"), "123")
//this.schema!!.decrypt(this.schema!!.raw, "123")
setSupportActionBar(findViewById(R.id.toolbar))

View File

@@ -7,7 +7,6 @@ import android.util.Log
import java.nio.ByteBuffer
import java.security.SecureRandom
import java.security.spec.KeySpec
import java.util.concurrent.CountDownLatch
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.SecretKeyFactory
@@ -57,22 +56,18 @@ class CryptoOperations {
}
val key: SecretKey = SecretKeySpec(aes_key, "AES")
val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
// Performing actual crypto operation
cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
cipher.init(Cipher.ENCRYPT_MODE, key, GCMParameterSpec(128, iv))
Log.i("Crypto", "Encrypt using ${String(aes_key)} '$plain' ${String(iv)}")
val ciphered = cipher.doFinal(plain.toByteArray(Charsets.UTF_8))
// Concat everything into one byte array
val byteBuffer: ByteBuffer = ByteBuffer.allocate(ciphered.size)
byteBuffer.put(ciphered)
Log.d("Crypto", "Encrypted $plain => ${String(byteBuffer.array())}")
return EncryptionResult(Base64.encodeToString(byteBuffer.array(), Base64.DEFAULT), salt, iv)
Log.d("Crypto", "Encrypted $plain => ${Base64.encodeToString(ciphered, Base64.NO_WRAP)}")
return EncryptionResult(Base64.encodeToString(ciphered, Base64.NO_WRAP), salt, iv)
}
fun decrypt(encrypted: String, key: String, iv: ByteArray, salt: ByteArray): String? {
fun decrypt(encrypted: String, key: String, iv: ByteArray, salt: ByteArray): String {
val key_bytes: ByteArray = hash(key.toCharArray(), salt).toByteArray(Charsets.UTF_8)
val aes_key: ByteArray = ByteArray(32)
@@ -84,17 +79,16 @@ class CryptoOperations {
aes_key.set(i, key_bytes[i])
}
// Decode Base64
val raw_encrypted = Base64.decode(encrypted, Base64.DEFAULT)
val encrypted_raw = Base64.decode(encrypted, Base64.NO_WRAP)
Log.i("Crypto", "Decrypt using ${String(aes_key)} '${String(raw_encrypted)}' ${String(iv)}")
Log.i("Crypto", "Decrypt using ${String(aes_key)} '${Base64.encodeToString(encrypted_raw, Base64.NO_WRAP)} (${encrypted_raw.size})' ${String(iv)}")
val key: SecretKey = SecretKeySpec(aes_key, "AES")
val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
val keySpec: SecretKey = SecretKeySpec(aes_key, "AES")
val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
// Performing actual crypto operation
cipher.init(Cipher.DECRYPT_MODE, key, IvParameterSpec(iv))
val ciphered = cipher.doFinal(raw_encrypted)
cipher.init(Cipher.DECRYPT_MODE, keySpec, GCMParameterSpec(128, iv))
val ciphered = cipher.doFinal(encrypted_raw)
// Concat everything into one byte array
val byteBuffer: ByteBuffer = ByteBuffer.allocate(ciphered.size)

View File

@@ -13,7 +13,6 @@ import com.google.zxing.integration.android.IntentResult
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
class MainActivity : AppCompatActivity() {
@@ -26,13 +25,10 @@ class MainActivity : AppCompatActivity() {
var dbHandler = CompressionHelper(this, null)
dbHandler.writableDatabase.execSQL("DELETE FROM `${CompressionHelper.TABLE_NAME}`;")
var dummy_email = Compression("ul", "https://nicolasklier.de:3000", null)
var dummy_custom_key = Compression("vb", "Note", null)
var dummy_custom_value = Compression("O4", "This is a small note I have to keep.", null)
var dummy_email = Compression("ul", "https://nicolasklier.de:3000", null, null)
var dummy_custom_key = Compression("vb", "Note", null, null)
var dummy_custom_value = Compression("O4", "This is a small note I have to keep.", null, null)
//CryptoOperations().hash("secretpassword".toCharArray(), CryptoOperations().nextIV())
val cryptoThread = HandlerThread("Encryption thread")
cryptoThread.start()
val encrypted_result = GlobalScope.async {
dbHandler.add("JtuB4O9M42", dummy_email)
@@ -40,7 +36,6 @@ class MainActivity : AppCompatActivity() {
dbHandler.add("JtuB4O9M42", dummy_custom_value)
Log.i("Main", "Encrypted target data to: ${CryptoOperations().encrypt("My cool key", "my secret")}")
}
dbHandler.writableDatabase.close()

View File

@@ -1,12 +1,12 @@
package com.github.mondei1.offpass
import android.content.Context
import android.util.Base64
import android.util.Log
import com.github.mondei1.offpass.entities.Compression
import com.github.mondei1.offpass.entities.CompressionHelper
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.broadcast
import kotlinx.coroutines.runBlocking
import java.lang.Error
@@ -71,7 +71,7 @@ class QRSchema {
fields[0] = fields[0].replace("%", "")
session_key = fields[0].substring(0, 10) // Get first 10 chars, which are the
// session key
this.title = fields[0].substring(11, fields[0].length)
this.title = fields[0].substring(10, fields[0].length)
} else {
this.title = fields[0]
}
@@ -121,18 +121,110 @@ class QRSchema {
+ fields[i].toString())
}
}
// Final step is to resolve any compressed values
}
Log.i("QR-Code schema", "Found: $session_key, $title, $username, $password, " +
"$email, $website_url. ${custom.toString()} and ${question_awnser.toString()}")
return true
}
/**
* This function will take all defined variables and converts them into the QR-Code schema
* This function will take an raw string input and will decrypt it.
*
* @return It returns the raw decrypted raw value.
*/
fun build() {
fun decrypt(raw: String, passphrase: String): String {
val parts = raw.split(":")
val iv = parts[1]
val salt = parts[2]
val encrypted_content = parts[3]
Log.i("Decrypt schema", "Give data: $encrypted_content")
this.decrypted_raw = CryptoOperations().decrypt(
encrypted_content, passphrase,
iv.toByteArray(), salt.toByteArray())
return this.decrypted_raw
}
/**
* This function will take all defined variables and converts them into the QR-Code schema.
*
* @param compress_values Takes an string array where a entry can be `website_url` in case of an URL or
* the key of an optional field. For a security question take the question as key.
*/
fun build(compress_values: Array<String>, passphrase: String): String {
/* First phase is to construct the encrypted data. */
val session_key = CryptoOperations().nextString(10) // used for
var used_compression: Boolean = false
var url_copy = website_url
if (compress_values.contains("website_url")) {
used_compression = true
val email_key = CryptoOperations().nextString(4)
this.db?.add(session_key, Compression(email_key, website_url, null, null))
url_copy = "\$$email_key"
}
var encrypted_content: String =
"${this.title}|${this.username}|${this.password}|${this.email}|${url_copy}|"
// Loop thought optional/custom fields
for (i in this.custom) {
if (compress_values.contains(i.key)) {
used_compression = true
var key_key = CryptoOperations().nextString(4)
var key_value = CryptoOperations().nextString(4)
this.db?.add(session_key,
Compression(key_key, i.key, null, null))
this.db?.add(session_key,
Compression(key_value, i.value, null, null))
encrypted_content += "(\$$key_key)\$$key_value|"
} else {
encrypted_content += "(${i.key})${i.value}|"
}
}
// Loop thought security questions
for (i in this.question_awnser) {
used_compression = true
if (compress_values.contains(i.key)) {
var key_key = CryptoOperations().nextString(4)
var key_value = CryptoOperations().nextString(4)
this.db?.add(session_key,
Compression(key_key, i.key, null, null))
this.db?.add(session_key,
Compression(key_value, i.value, null, null))
encrypted_content += "()\$$key_key%\$$key_value|"
} else {
encrypted_content += "()${i.key}%${i.value}|"
}
}
encrypted_content = encrypted_content.dropLast(1)
if (used_compression) encrypted_content = "%$session_key%$encrypted_content"
Log.i("QR-Code Builder", "Constructed encrypted content: $encrypted_content")
// Now, let's encrypt that
val enc = runBlocking {
CryptoOperations().encrypt(passphrase, encrypted_content)
}
// TODO: Make schema version dynamic (currently hardcoded)
var final = "op1:" +
"${String(enc.iv)}:" +
"${String(enc.salt)}:" +
enc.result
.replace("\n", "")
Log.i("QR-Code Builder", "Returning final result: $final")
this.raw = final
return final
}

View File

@@ -44,8 +44,6 @@ class TextInput : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
head.text = arg_head
title.background = null
title.hint = arg_title
}
companion object {

View File

@@ -4,10 +4,12 @@ class Compression {
var key: String = "DEFAULT"
var value: String? = null
var iv: ByteArray? = null
var salt: ByteArray? = null
constructor(key: String, value: String, iv: ByteArray?) {
constructor(key: String, value: String, iv: ByteArray?, salt: ByteArray?) {
this.key = key
this.value = value
this.iv = iv
this.salt = salt
}
}

View File

@@ -4,6 +4,7 @@ import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.util.Base64
import android.util.Log
import com.github.mondei1.offpass.CryptoOperations
import kotlinx.coroutines.GlobalScope
@@ -71,6 +72,7 @@ class CompressionHelper(context: Context, factory: SQLiteDatabase.CursorFactory?
}
val decrypted_result = GlobalScope.async {
// TODO: Is a list even required?
CryptoOperations().decrypt(list[0], session_key, iv, salt)
}

View File

@@ -75,7 +75,7 @@
</androidx.appcompat.widget.Toolbar>
<FrameLayout
android:id="@+id/title"
android:id="@+id/title_box"
android:name="com.github.mondei1.offpass.TextInput"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -92,6 +92,6 @@
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
app:layout_constraintTop_toBottomOf="@+id/title_box" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -17,7 +17,7 @@
android:textSize="20sp" />
<EditText
android:id="@+id/title"
android:id="@+id/title_box"
style="@style/Widget.AppCompat.EditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@@ -1,5 +1,6 @@
<resources>
<string name="app_name">OffPass</string>
<string name="qr_schema_support">1</string>
<string name="title_activity_create">CreateActivity</string>
<!--
This string is used for square devices and overridden by hello_world in