Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
# whisper-ui
![](img-doc/whisper.png) Secure and very easy to use sending of encrypted data anywhere (browser ui)

## idea
Make it super easy to locally encrypt sensible data for only specific recipients ensuring privacy, integrity and compliance on whatever way the data is transported.
## Motivation
Make it super easy to locally encrypt sensible data for designated recipients ensuring privacy, integrity and compliance on whatever way the data is transported. Keys should be considered throw away material and not be reused often in order to render the transported cryptograms useless, even if they are retained in e.g. mailboxes.

## How does it work?
![](img-doc/how-does-it-work.png)
This is quite simple: Whisper! uses [asymmetric cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) and
the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) to create two keys. One can be used for encryption and the other for decryption. The latter should not leave your browser's local storage. To exchange sensitive data the following steps are executed:
1. The recipients send their public key parts to the sender and use whatever communication channel they see fit.
1. The sender uses the key parts of all intended recipients, encrypts the data locally in the browser and sends the resulting cryptogram to the recipients.
1. The recipients decrypt the cryptogram locally in their browser and save the sensitive data. They may throw away their keys rendering the cryptogram useless.

Thus the sensitive data never leaves the senders' and recipients' devices.

### Create and encrypt locally in you browser
![](img-doc/create-whisper.png)
Drop recipients' keys and some sensitive data, then locally and download cryptograms:
<div style="display: flex;">
<img src="img-doc/create-and-send-1.png" alt="drop keys and data" style="max-height:40em;" />
&nbsp;
<img src="img-doc/create-and-send-2.png" alt="encrypt and download" style="max-height:40em;" />
</div>

### Receive and decrpt locally in your browser
![](img-doc/receive-whisper.png)
### Receive and decrypt locally in your browser
Drop encrypted stuff you received, then decrypt locally and download result:
<div style="display: flex;">
<img src="img-doc/receive-1.png" alt="drop cryptogram" style="max-height:40em;" />
&nbsp;
<img src="img-doc/receive-2.png" alt="decrypt and download" style="max-height:40em;" />
</div>

## Features (free)
* A keypair is automatically generated locally and stored in the browser's IndexedDB
* The public part of the keypair can be copied and desitribiuted to those who want to send you sensitive data
* The public part of the keypair can be copied and distributed to those who want to send you sensitive data
* The private part remains local and is the only way to decrypt data addressed to you
* Use the hosted version (the good stuff happens locally anyway) or self host and modify it
* TODO: List security and compliance features
Expand All @@ -25,14 +45,14 @@ Make it super easy to locally encrypt sensible data for only specific recipients
* Synchronization of the created cryptograms to the designated recepients (no need to send them separately)
* OAuth2 / OIDC login with your IDP or e-mail accounts of your org
* optional audit / usage log
* support with your compliance frameworks and certifications
* TODO: continue


## Stack and development - very early experimental phase ;)
* plain HTML, CSS
* Typescript

some magnificent and lightweigt libraries
some magnificent and lightweight libraries
* [jose](https://github.com/panva/jose) library
* [Pure](https://pure-css.github.io/)
* [Iconify](https://pictogrammers.com/docs/guides/iconify/) and [Material Design Icons](https://pictogrammers.com/library/mdi/)
Expand All @@ -43,12 +63,7 @@ Use [Bun](https://bun.sh/) to run build script that compiles icons
bun run ./build/build-iconify.ts
```

Use [Bun](https://bun.sh/) for on the fly typescript compilation
Use [Bun](https://bun.sh/) for on the fly typescript compilation and serving the app
```sh
bun build src/* --outdir dist --watch
bun build index.html
```

and a http server of your choise to serve, e.g.
```sh
python3 -m http.server 8080
```
1 change: 1 addition & 0 deletions build/build-iconify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const chosenIcons: Array<string> = [
'check',
'close',
'github',
'help-circle-outline',
'human-greeting',
'information-outline',
'key-chain',
Expand Down
Binary file added img-doc/create-and-send-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img-doc/create-and-send-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img-doc/create-whisper.png
Binary file not shown.
Binary file added img-doc/how-does-it-work.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img-doc/receive-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img-doc/receive-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed img-doc/receive-whisper.png
Binary file not shown.
3 changes: 3 additions & 0 deletions img/how-does-it-work.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 64 additions & 14 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
<li class="pure-menu-item">
<a href="https://github.com/syncorix-com/whisper-ui"
class="pure-menu-link selectable-image-container"><span
class="button-icon icon--mdi icon--mdi--github"></span><br /><span
class="additional-info">to GitHub</span></a>
class="button-icon icon--mdi icon--mdi--github"></span><br /><span class="additional-info">to
GitHub</span></a>
</li>
</ul>
</div>
Expand Down Expand Up @@ -232,13 +232,13 @@ <h3 class="title">Welcome</h3>
<span class="marker-icon icon--mdi icon--mdi--human-greeting"></span>
<span
x-show="receivedScreen.encryptedFiles.length == 0 && receivedScreen.decryptedFiles.length ==0">Welcome!
In order to decypher encypted data that has been sent sent to you, please drop at least one
file into the box.</span>
In order to decrypt prviously encrypted data that has been sent sent to you, please drop at
least one file into the box.</span>
<span
x-show="receivedScreen.encryptedFiles.length > 0 && receivedScreen.decryptedFiles.length == 0">Nice!
Now you and only you can decypt the content using your locally stored private key.</span>
Now you and only you can decrypt the content using your locally stored private key.</span>
<span x-show="receivedScreen.decryptedFiles.length > 0">Great!
The files have been decypted and can be downloaded.</span>
The files have been decrypted and can be downloaded.</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -307,21 +307,46 @@ <h3 class="title">Complete!</h3>
<!-- ==================== YOU / ACCOUNT SCREEN ==================== -->
<div class="pure-g"
x-show="engineState != CryptoEngineState.Unknown && personalPublicKey && personalPrivateKey && activeScreen == WhisperScreen.Account">
<div class="pure-u-1">
<div class="pure-u-1 pure-u-lg-1-2">
<div class="content-box">
<h3 class="title">Your keys</h3>
<h3 class="title">What can Whisper! do?</h3>
<div class="box-with-icon-and-text">
<span class="marker-icon icon--mdi icon--mdi--help-circle-outline"></span>
<div>
<p>
You can either head over to the <a href="#"
x-on:click="activeScreen = WhisperScreen.Send"><span
class="icon--mdi icon--mdi--call-made"></span> Send</a> section to encrypt
something for somebody who has given you their Whisper! public key.
</p>
<p>
Or you use the <a href="#" x-on:click="activeScreen = WhisperScreen.Receive"><span
class="icon--mdi icon--mdi--call-received"></span>
Receive</a> section to decrypt previously encrypted data sent to you. To receive a file
that can only be decrypted by you, hand your current Whisper! public key to the sender(s).
</p>
</div>
</div>
</div>
</div>
<div class="pure-u-1 pure-u-lg-1-2">
<div class="content-box">
<h3 id="your_keys" class="title">Your keys</h3>
<div class="box-with-icon-and-text">
<span class="marker-icon icon--mdi icon--mdi--key-chain"></span>
<div>
<p>
We have successfully created a keypair for you and stored it in your local browser! You can
download the public key here. It is no secret and can be sent to anyone you want to receive
whispers from.
download the Whisper! public key here. It is not a secret and can be sent to anyone you wish
to
receive whispers from.
</p>
<p x-show="personalPublicKey && personalPublicKey.xKidHint">
Please note that if you clear your browser data for this site, existing keys <u>will be
lost</u> and new keys will be generated. This is by design, please ensure that senders
have your latest public key file.
<u>Please note</u>, that if you clear your browser data for this site, existing keys <u>will
be
lost</u> and new keys will be generated. This is by design, so please ensure that
senders
have your latest Whisper! public key file.
</p>
<p x-show="personalPublicKey && !personalPublicKey.xKidHint">
Before downloading and distributing your key, please provide some info on who you might
Expand Down Expand Up @@ -361,7 +386,7 @@ <h3 class="title">About Whisper!</h3>
<div>
Whisper! was created by <a href="https://syncorix.com">Syncorix</a> in order to securely
exchange sensitive data with others. It
runs in your browser and does not transmit data to us. In order to make it available on the
runs in your browser and does not transmit any data to us. In order to make it available on the
internet, it needs to be hosted. We chose our hosters with regard to privacy.
<br />
Please also see
Expand All @@ -374,6 +399,31 @@ <h3 class="title">About Whisper!</h3>
</div>
</div>
</div>
<div class="pure-u-1">
<div class="content-box">
<h3 class="title">How does Whisper! work</h3>
<div style="text-align: center;">
<img src="img/how-does-it-work.svg" alt="how does it work" style="max-width: 100%;" />
</div>
<div>
This is quite simple: Whisper! uses <a
href="https://en.wikipedia.org/wiki/Public-key_cryptography">asymmetric cryptography</a> and
the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API">Web Crypto API</a>
to create two keys. One can be used for encryption and the other for decryption. The latter should
not
leave your browser's local storage. To exchange sensitive data the following steps are executed:
<ol>
<li>The recipients send their public key parts to the sender and use whatever communication
channel they see fit.</li>
<li>The sender uses the key parts of all intended recipients, encrypts the data locally in
the browser and sends the resulting cryptogram to the recipients.</li>
<li>The recipients decrypt the cryptogram locally in their browser and save the sensitive data.
They may throw away their keys rendering the cryptogram useless.</li>
</ol>
Thus the sensitive data never leaves the senders' and recipients' devices.
</div>
</div>
</div>
<div class="pure-u-1">
<div class="content-box">
<h3 class="title">Security of Transmission</h3>
Expand Down
2 changes: 1 addition & 1 deletion src/whisper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ function executeDecryption() {
crypto.decryptFile(f.jwe, jwk)
.then(d => ({ name: tryExtractFileName(f.name), data: base64(d) } as DecryptedFile))
.then(r => store.receivedScreen.decryptedFiles.push(r))
.then(() => console.log("Successully decypted %s with kid %s.", f.name, jwk.kid))
.then(() => console.log("Successully decrypted %s with kid %s.", f.name, jwk.kid))
.catch(e => console.warn("Failed to decrypt %s", f.name, e))
})
}
Expand Down