Skip to content

Commit

Permalink
Merge pull request #98 from Arctosoft/develop
Browse files Browse the repository at this point in the history
Valv v2
  • Loading branch information
hej2010 authored Dec 8, 2024
2 parents dd06428 + 9dd02b4 commit 9a14773
Show file tree
Hide file tree
Showing 140 changed files with 10,593 additions and 3,033 deletions.
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions .idea/runConfigurations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 36 additions & 29 deletions ENCRYPTION.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,62 @@
This is the encryption docs for file structure version 2.

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

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

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

## Encrypted file structure
![Encrypted file structure image](/images/encryption.jpg)
![Encrypted file structure image](/images/encryption_v2.jpg)

## File types/names

The following filename prefixes are used:
- `.valv.i.1-` for image files
- `.valv.g.1-` for GIF files
- `.valv.v.1-` for video files
- `.valv.n.1-` for note files
- `.valv.t.1-` for thumbnail files
The following filename suffixes are used:
- `-i.valv` for image files
- `-g.valv` for GIF files
- `-v.valv` for video files
- `-x.valv` for text files
- `-n.valv` for note files
- `-t.valv` for thumbnail files

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

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

`.valv.i.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ` has a thumbnail
`aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ-i.valv` has a thumbnail

`.valv.t.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ`.
`aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ-t.valv`.

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

All text and strings are encoded as UTF-8.

## Encrypting
The app creates the encrypted files in the following way:
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.
1. Generate a random 16 byte salt, a 12 byte IV and 12 check bytes.
2. Create an unencrypted output stream.
3. Write the salt.
4. Write the IV.
5. If the file is a thumbnail, write the check bytes.
6. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted.
7. If the file is a thumbnail, write the check bytes.
8. Write a newline character followed by the original filename and another newline character (`'\n' + name + '\n'`).
9. Write the file data.
3. Write the encrypted file structure version (4 bytes, integer)
4. Write the salt.
5. Write the IV.
6. Write the iteration count used for key generation (4 bytes, integer)
7. Write the check bytes.
8. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted.
9. Write the check bytes.
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'`).
11. Write the file data.

## Decrypting
The app reads the encrypted files in the following way:
1. Create an unencrypted input stream.
2. Read the 16 byte salt.
3. Read the 12 byte IV.
4. If the file is a thumbnail, read the 12 check bytes.
5. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data.
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.
7. Read a newline character (`0x0A`) followed by the original filename and another newline character.
8. Read the file data.

A Python script to decrypt .valv files can be found in [this issue comment](https://github.com/Arctosoft/Valv-Android/issues/33#issuecomment-1974834924).
2. Read the encrypted file structure version (4 bytes, integer)
3. Read the 16 byte salt.
4. Read the 12 byte IV.
5. Read the iteration count used for key generation (4 bytes, integer)
6. Read the 12 check bytes.
7. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data.
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.
9. Read a newline character (`0x0A`) followed by the JSON object string and another newline character.
10. Read the file data.

57 changes: 57 additions & 0 deletions ENCRYPTION_V1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
This is the encryption docs for file structure version 1.

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

The key algorithm is `PBKDF2withHmacSHA512` with 20000 iterations and a 256-bit key length.

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.

## Encrypted file structure
![Encrypted file structure image](/images/encryption_v1.jpg)

## File types/names

The following filename prefixes are used:
- `.valv.i.1-` for image files
- `.valv.g.1-` for GIF files
- `.valv.v.1-` for video files
- `.valv.x.1-` for text files
- `.valv.n.1-` for note files
- `.valv.t.1-` for thumbnail files

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

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

`.valv.i.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ` has a thumbnail

`.valv.t.1-aLFshh71iywWo7HXtEcOtZNVJe-Ot7iQ`.

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

## Encrypting
The app creates the encrypted files in the following way:
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.
2. Create an unencrypted output stream.
3. Write the salt.
4. Write the IV.
5. If the file is a thumbnail, write the check bytes.
6. Pass the output stream into a cipher (encrypted) output stream. Everything below is encrypted.
7. If the file is a thumbnail, write the check bytes.
8. Write a newline character followed by the original filename and another newline character (`'\n' + name + '\n'`).
9. Write the file data.

## Decrypting
The app reads the encrypted files in the following way:
1. Create an unencrypted input stream.
2. Read the 16 byte salt.
3. Read the 12 byte IV.
4. If the file is a thumbnail, read the 12 check bytes.
5. Pass the input stream into a cipher (encrypted) input stream. Everything below is read from encrypted data.
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.
7. Read a newline character (`0x0A`) followed by the original filename and another newline character.
8. Read the file data.

A Python script to decrypt .valv files can be found in [this issue comment](https://github.com/Arctosoft/Valv-Android/issues/33#issuecomment-1974834924).
72 changes: 0 additions & 72 deletions app/build.gradle

This file was deleted.

84 changes: 84 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.about.libraries)
}

android {
namespace = "se.arctosoft.vault"
compileSdk = 35

defaultConfig {
applicationId = "se.arctosoft.vault"
minSdk = 28
targetSdk = 35
versionCode = 31
versionName = "2.0.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
applicationIdSuffix = ".dev"
}
applicationVariants.all {
val variant = this
variant.outputs.map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
.forEach { output ->
val outputFileName =
"Vault_${variant.versionCode}_${variant.versionName}_${variant.buildType.name}.apk"
output.outputFileName = outputFileName
}
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildFeatures {
viewBinding = true
buildConfig = true
}
}

dependencies {
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
testImplementation(libs.junit)

implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.constraintlayout)
implementation(libs.navigation.fragment)
implementation(libs.navigation.ui)
implementation(libs.preference)
implementation(libs.activity)

implementation(libs.security.crypto)
implementation(libs.media3.exoplayer)
implementation(libs.media3.ui)
implementation(libs.preferences)
annotationProcessor(libs.glide.annotation)

implementation(libs.glide)
implementation(libs.about.libraries)
implementation(libs.about.libraries.compose)
}

aboutLibraries {
configPath = "config"
// Remove the "generated" timestamp to allow for reproducible builds
excludeFields = arrayOf("generated")
}
3 changes: 0 additions & 3 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
# hide the original source file name.
#-renamesourcefileattribute SourceFile

-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep class com.bumptech.glide.GeneratedAppGlideModule

# remove all log prints
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
Expand Down
Loading

0 comments on commit 9a14773

Please sign in to comment.