From cd0e7e8817f52c85509c02a4fad2073f1e5ba9a8 Mon Sep 17 00:00:00 2001
From: 0xBlockPay <0xblockpay@gmail.com>
Date: Mon, 6 May 2024 13:30:03 +0200
Subject: [PATCH] [#130] Shamir's secret sharing for seed
---
.idea/.gitignore | 3 +
.idea/.name | 1 +
.idea/compiler.xml | 6 ++
.idea/deploymentTargetSelector.xml | 13 +++++
.idea/kotlinc.xml | 6 ++
.idea/migrations.xml | 10 ++++
.idea/misc.xml | 10 ++++
impl/build.gradle | 2 +
.../seedvaultimpl/model/SeedDetails.kt | 7 +++
.../ui/seeddetail/SeedDetailViewModel.kt | 58 +++++++++++++++++++
10 files changed, 116 insertions(+)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/.name
create mode 100644 .idea/compiler.xml
create mode 100644 .idea/deploymentTargetSelector.xml
create mode 100644 .idea/kotlinc.xml
create mode 100644 .idea/migrations.xml
create mode 100644 .idea/misc.xml
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..aa11acd
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Wallet-API-SDK
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b589d56
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..b399ffb
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..fe63bb6
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..0ad17cb
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/impl/build.gradle b/impl/build.gradle
index 33eaf03..9597f44 100644
--- a/impl/build.gradle
+++ b/impl/build.gradle
@@ -67,6 +67,8 @@ protobuf {
}
dependencies {
+ implementation group: 'com.codahale', name: 'shamir', version: '0.7.0'
+
implementation project(path: ':seedvault')
implementation 'androidx.activity:activity-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
diff --git a/impl/src/main/java/com/solanamobile/seedvaultimpl/model/SeedDetails.kt b/impl/src/main/java/com/solanamobile/seedvaultimpl/model/SeedDetails.kt
index 2efc36e..4d5a44b 100644
--- a/impl/src/main/java/com/solanamobile/seedvaultimpl/model/SeedDetails.kt
+++ b/impl/src/main/java/com/solanamobile/seedvaultimpl/model/SeedDetails.kt
@@ -57,4 +57,11 @@ data class SeedDetails(
result = 31 * result + unlockWithBiometrics.hashCode()
return result
}
+ private fun createString(): String {
+ return "{\"seed:\"$seed, \"name\": $name }"
+ }
+
+ fun getValue() :ByteArray {
+ return createString().toByteArray()
+ }
}
diff --git a/impl/src/main/java/com/solanamobile/seedvaultimpl/ui/seeddetail/SeedDetailViewModel.kt b/impl/src/main/java/com/solanamobile/seedvaultimpl/ui/seeddetail/SeedDetailViewModel.kt
index e9f24fc..5a58c9e 100644
--- a/impl/src/main/java/com/solanamobile/seedvaultimpl/ui/seeddetail/SeedDetailViewModel.kt
+++ b/impl/src/main/java/com/solanamobile/seedvaultimpl/ui/seeddetail/SeedDetailViewModel.kt
@@ -17,6 +17,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import java.security.MessageDigest
+import java.security.SecureRandom
+import javax.crypto.Cipher
+import javax.crypto.KeyGenerator
+import javax.crypto.SecretKey
+import javax.crypto.spec.IvParameterSpec
import kotlin.random.Random
class SeedDetailViewModel private constructor(
@@ -111,6 +117,30 @@ class SeedDetailViewModel private constructor(
SeedDetails(seedBytes, phrase, it.name.ifBlank { null }, it.pin, it.enableBiometrics)
}
+ //Construct algorithm
+ val scheme = com.codahale.shamir.Scheme(SecureRandom(), 5, 3)
+
+ //Generate Key
+ val key = generateAESKeyFromString("password")
+
+ //Encrypt seedDetails
+ val aes = aesEncrypt( seedDetails.getValue(), key)
+
+ //Split seed
+ val secrets = scheme.split(aes)
+
+ val hexs = secrets.values.forEach{v -> v.toHex()}
+
+ Log.i(TAG, "Successfully created hex's parts $hexs")
+
+ val joinSecret = scheme.join(secrets)
+ val secretArray = aesDecrypt(joinSecret, key)
+
+ val seedDetailsString = String(secretArray)
+
+ Log.i(TAG, "Successfully created Seed $seedDetailsString")
+
+
Log.i(TAG, "Successfully created Seed $seedDetails; committing to SeedRepository")
when (val mode = mode) { // immutable snapshot of mode
is NewSeedMode -> {
@@ -205,3 +235,31 @@ data class PreAuthorizeSeed(
val purpose: Authorization.Purpose
)
+
+fun ByteArray.toHex(): String = joinToString(separator = "") { eachByte ->
+ "%02x".format(eachByte)
+}
+
+fun aesDecrypt(encryptedData: ByteArray, secretKey: SecretKey): ByteArray {
+ val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
+ val ivParameterSpec = IvParameterSpec(ByteArray(16)) // W produkcji użyj bezpiecznego IV
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)
+ return cipher.doFinal(encryptedData)
+}
+fun aesEncrypt(data: ByteArray, secretKey: SecretKey): ByteArray {
+ val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
+ val ivParameterSpec = IvParameterSpec(ByteArray(16)) // Use a secure IV in production
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)
+ return cipher.doFinal(data)
+}
+
+fun generateAESKeyFromString(inputString: String, keySize: Int = 256): SecretKey {
+ val messageDigest = MessageDigest.getInstance("SHA-256")
+ val hashBytes = messageDigest.digest(inputString.toByteArray())
+
+ val keyGenerator = KeyGenerator.getInstance("AES")
+ keyGenerator.init(keySize, SecureRandom(hashBytes))
+
+ return keyGenerator.generateKey()
+}
+