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() +} +