Skip to content

Commit 9a14773

Browse files
authored
Merge pull request #98 from Arctosoft/develop
Valv v2
2 parents dd06428 + 9dd02b4 commit 9a14773

File tree

140 files changed

+10593
-3033
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

140 files changed

+10593
-3033
lines changed

.idea/compiler.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations.xml

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ENCRYPTION.md

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,62 @@
1+
This is the encryption docs for file structure version 2.
12

23
# File encryption
34
Files are encrypted using the `ChaCha20/NONE/NoPadding` cipher in Android. See [Android Ciphers](https://developer.android.com/reference/javax/crypto/Cipher) for details.
45

5-
The key algorithm is `PBKDF2withHmacSHA512` with 20000 iterations and a 256-bit key length.
6+
The key algorithm is `PBKDF2withHmacSHA512` with 50000 iterations (default, can be changed) and a 256-bit key length.
67

7-
The salt is 16 bytes and the IV is 12 bytes. An additional 12 bytes is used in some files to check if the supplied password can decrypt the file, see details below.
8+
The salt is 16 bytes and the IV is 12 bytes. An additional 12 bytes is used to check if the supplied password can decrypt the file, see details below.
89

910
## Encrypted file structure
10-
![Encrypted file structure image](/images/encryption.jpg)
11+
![Encrypted file structure image](/images/encryption_v2.jpg)
1112

1213
## File types/names
1314

14-
The following filename prefixes are used:
15-
- `.valv.i.1-` for image files
16-
- `.valv.g.1-` for GIF files
17-
- `.valv.v.1-` for video files
18-
- `.valv.n.1-` for note files
19-
- `.valv.t.1-` for thumbnail files
15+
The following filename suffixes are used:
16+
- `-i.valv` for image files
17+
- `-g.valv` for GIF files
18+
- `-v.valv` for video files
19+
- `-x.valv` for text files
20+
- `-n.valv` for note files
21+
- `-t.valv` for thumbnail files
2022

2123
The number represents the file structure version (for future expansion/changes).
2224

23-
Filenames are generated randomly and are `PREFIX_LENGTH + 32 chars` long.
25+
Filenames are generated randomly and are `32 chars + SUFFIX_LENGTH` long.
2426
Every media file has a corresponding thumbnail with the same name. For example, an image file named
2527

26-
`.valv.i.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ` has a thumbnail
28+
`aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ-i.valv` has a thumbnail
2729

28-
`.valv.t.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ`.
30+
`aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ-t.valv`.
2931

3032
Similarly, a note has the same name as its media file.
3133

34+
All text and strings are encoded as UTF-8.
35+
3236
## Encrypting
3337
The app creates the encrypted files in the following way:
34-
1. Generate a random 16 byte salt and 12 byte IV. If the file is a thumbnail it also generates an additional 12 check bytes.
38+
1. Generate a random 16 byte salt, a 12 byte IV and 12 check bytes.
3539
2. Create an unencrypted output stream.
36-
3. Write the salt.
37-
4. Write the IV.
38-
5. If the file is a thumbnail, write the check bytes.
39-
6. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted.
40-
7. If the file is a thumbnail, write the check bytes.
41-
8. Write a newline character followed by the original filename and another newline character (`'\n' + name + '\n'`).
42-
9. Write the file data.
40+
3. Write the encrypted file structure version (4 bytes, integer)
41+
4. Write the salt.
42+
5. Write the IV.
43+
6. Write the iteration count used for key generation (4 bytes, integer)
44+
7. Write the check bytes.
45+
8. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted.
46+
9. Write the check bytes.
47+
10. Write a newline character followed by a JSON object as an string containing the original filename and another newline character (`'\n' + "{\"originalName\":\"file.jpg\"}" + '\n'`).
48+
11. Write the file data.
4349

4450
## Decrypting
4551
The app reads the encrypted files in the following way:
4652
1. Create an unencrypted input stream.
47-
2. Read the 16 byte salt.
48-
3. Read the 12 byte IV.
49-
4. If the file is a thumbnail, read the 12 check bytes.
50-
5. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data.
51-
6. If the file is a thumbnail, read the check bytes. If the unencrypted check bytes does not equal the check bytes in the encrypted part, the given password is invalid.
52-
7. Read a newline character (`0x0A`) followed by the original filename and another newline character.
53-
8. Read the file data.
54-
55-
A Python script to decrypt .valv files can be found in [this issue comment](https://github.com/Arctosoft/Valv-Android/issues/33#issuecomment-1974834924).
53+
2. Read the encrypted file structure version (4 bytes, integer)
54+
3. Read the 16 byte salt.
55+
4. Read the 12 byte IV.
56+
5. Read the iteration count used for key generation (4 bytes, integer)
57+
6. Read the 12 check bytes.
58+
7. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data.
59+
8. Read the check bytes. If the unencrypted check bytes does not equal the check bytes in the encrypted part, the given password is invalid.
60+
9. Read a newline character (`0x0A`) followed by the JSON object string and another newline character.
61+
10. Read the file data.
62+

ENCRYPTION_V1.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
This is the encryption docs for file structure version 1.
2+
3+
# File encryption
4+
Files are encrypted using the `ChaCha20/NONE/NoPadding` cipher in Android. See [Android Ciphers](https://developer.android.com/reference/javax/crypto/Cipher) for details.
5+
6+
The key algorithm is `PBKDF2withHmacSHA512` with 20000 iterations and a 256-bit key length.
7+
8+
The salt is 16 bytes and the IV is 12 bytes. An additional 12 bytes is used in some files to check if the supplied password can decrypt the file, see details below.
9+
10+
## Encrypted file structure
11+
![Encrypted file structure image](/images/encryption_v1.jpg)
12+
13+
## File types/names
14+
15+
The following filename prefixes are used:
16+
- `.valv.i.1-` for image files
17+
- `.valv.g.1-` for GIF files
18+
- `.valv.v.1-` for video files
19+
- `.valv.x.1-` for text files
20+
- `.valv.n.1-` for note files
21+
- `.valv.t.1-` for thumbnail files
22+
23+
The number represents the file structure version (for future expansion/changes).
24+
25+
Filenames are generated randomly and are `PREFIX_LENGTH + 32 chars` long.
26+
Every media file has a corresponding thumbnail with the same name. For example, an image file named
27+
28+
`.valv.i.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ` has a thumbnail
29+
30+
`.valv.t.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ`.
31+
32+
Similarly, a note has the same name as its media file.
33+
34+
## Encrypting
35+
The app creates the encrypted files in the following way:
36+
1. Generate a random 16 byte salt and 12 byte IV. If the file is a thumbnail it also generates an additional 12 check bytes.
37+
2. Create an unencrypted output stream.
38+
3. Write the salt.
39+
4. Write the IV.
40+
5. If the file is a thumbnail, write the check bytes.
41+
6. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted.
42+
7. If the file is a thumbnail, write the check bytes.
43+
8. Write a newline character followed by the original filename and another newline character (`'\n' + name + '\n'`).
44+
9. Write the file data.
45+
46+
## Decrypting
47+
The app reads the encrypted files in the following way:
48+
1. Create an unencrypted input stream.
49+
2. Read the 16 byte salt.
50+
3. Read the 12 byte IV.
51+
4. If the file is a thumbnail, read the 12 check bytes.
52+
5. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data.
53+
6. If the file is a thumbnail, read the check bytes. If the unencrypted check bytes does not equal the check bytes in the encrypted part, the given password is invalid.
54+
7. Read a newline character (`0x0A`) followed by the original filename and another newline character.
55+
8. Read the file data.
56+
57+
A Python script to decrypt .valv files can be found in [this issue comment](https://github.com/Arctosoft/Valv-Android/issues/33#issuecomment-1974834924).

app/build.gradle

Lines changed: 0 additions & 72 deletions
This file was deleted.

app/build.gradle.kts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
plugins {
2+
alias(libs.plugins.android.application)
3+
alias(libs.plugins.about.libraries)
4+
}
5+
6+
android {
7+
namespace = "se.arctosoft.vault"
8+
compileSdk = 35
9+
10+
defaultConfig {
11+
applicationId = "se.arctosoft.vault"
12+
minSdk = 28
13+
targetSdk = 35
14+
versionCode = 31
15+
versionName = "2.0.0"
16+
17+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
18+
}
19+
20+
buildTypes {
21+
release {
22+
isMinifyEnabled = true
23+
proguardFiles(
24+
getDefaultProguardFile("proguard-android-optimize.txt"),
25+
"proguard-rules.pro"
26+
)
27+
}
28+
debug {
29+
isMinifyEnabled = false
30+
proguardFiles(
31+
getDefaultProguardFile("proguard-android-optimize.txt"),
32+
"proguard-rules.pro"
33+
)
34+
applicationIdSuffix = ".dev"
35+
}
36+
applicationVariants.all {
37+
val variant = this
38+
variant.outputs.map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
39+
.forEach { output ->
40+
val outputFileName =
41+
"Vault_${variant.versionCode}_${variant.versionName}_${variant.buildType.name}.apk"
42+
output.outputFileName = outputFileName
43+
}
44+
}
45+
}
46+
compileOptions {
47+
sourceCompatibility = JavaVersion.VERSION_17
48+
targetCompatibility = JavaVersion.VERSION_17
49+
}
50+
buildFeatures {
51+
viewBinding = true
52+
buildConfig = true
53+
}
54+
}
55+
56+
dependencies {
57+
androidTestImplementation(libs.ext.junit)
58+
androidTestImplementation(libs.espresso.core)
59+
testImplementation(libs.junit)
60+
61+
implementation(libs.appcompat)
62+
implementation(libs.material)
63+
implementation(libs.constraintlayout)
64+
implementation(libs.navigation.fragment)
65+
implementation(libs.navigation.ui)
66+
implementation(libs.preference)
67+
implementation(libs.activity)
68+
69+
implementation(libs.security.crypto)
70+
implementation(libs.media3.exoplayer)
71+
implementation(libs.media3.ui)
72+
implementation(libs.preferences)
73+
annotationProcessor(libs.glide.annotation)
74+
75+
implementation(libs.glide)
76+
implementation(libs.about.libraries)
77+
implementation(libs.about.libraries.compose)
78+
}
79+
80+
aboutLibraries {
81+
configPath = "config"
82+
// Remove the "generated" timestamp to allow for reproducible builds
83+
excludeFields = arrayOf("generated")
84+
}

app/proguard-rules.pro

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
# hide the original source file name.
2121
#-renamesourcefileattribute SourceFile
2222

23-
-keep public class * extends com.bumptech.glide.module.AppGlideModule
24-
-keep class com.bumptech.glide.GeneratedAppGlideModule
25-
2623
# remove all log prints
2724
-assumenosideeffects class android.util.Log {
2825
public static boolean isLoggable(java.lang.String, int);

0 commit comments

Comments
 (0)