A simple, fault-tolerant, and easy-to-audit password manager. Only ONE dependency: Stanford Javascript Crypto Library https://pwm.sequentialread.com
|
6 months ago | |
---|---|---|
static | 6 months ago | |
.gitignore | 6 months ago | |
Dockerfile | 6 months ago | |
LICENSE | 3 years ago | |
ReadMe.md | 6 months ago | |
build.sh | 6 months ago | |
index.html.gotemplate | 6 months ago | |
screenshot.png | 3 years ago | |
server.go | 6 months ago |
This is a Golang / HTML5 / vanilla JavaScript web-application which stores encrypted text files in three places:
localStorage
in the browserTry it! (https://pwm.sequentialread.com)
OR run it yourself in docker:
docker run \
-p 8073:8073 \
-v "/Users/exampleUser/Desktop/encrypted-passwords:/data" \
-e SEQUENTIAL_READ_PWM_AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE \
-e SEQUENTIAL_READ_PWM_AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
-e SEQUENTIAL_READ_PWM_S3_BUCKET_NAME=my-encrypted-password-bucket \
-e SEQUENTIAL_READ_PWM_S3_BUCKET_REGION=us-west-2 \
sequentialread/sequentialread-password-manager:1.1.0
See "Hosting it yourself" for more information.
First and foremost, the application is easy to audit since it has only one dependency: sjcl.js, AKA the Stanford JavaScript Crypto Library.
There is nothing that pulls in dependencies, no bundling step, etc. There is only one place where XMLHttpRequest
is created, and the request body is encrypted in the same place. Same goes for localStorage
.
It was designed that way to strengthen the claim that "everything it sends out from the javascript VM is AES encrypted with the key you chose".
It uses the Service Worker API to ensure that even if my server goes down, the app still loads.
It also has its own AWS Credential with access to the bucket, so you can still access S3 if my server goes down.
It will also work even if your device has no internet connection, of course any changes will not be sent to the server or to S3 until you connect again and prompt the app to update the file again.
It uses a naive approach to keep all 3 data stores in sync: When writing, it will attempt to write to all 3 and tolerate failures. When reading, it will compare the lastUpdated
timestamps on all versions that it received, and if they don't match or if one is missing, it will issue a PUT
with the most up-to-date version.
That means if you happen to make conflicting changes, there is no real conflict resolution. The latest one wins.
You are allowed to use whatever seed you want for your AES key. If you pick a weak seed and get hacked, that is your fault. The application warned you about it. It was even red, bold and underlined!
The application includes a timestamp + mouse-movement + SHA256 based entropy generator to create a secure ~128 bit key, encoded in base 10,000. It will appear as a collection of a few english words/phrases. An example:
bedrooms confirmation decor generic wondering temperatures bm retreat beer
Assuming the attacker had access to the ciphertext and could use top-of-the-line hardware (A Bitmain Antminer S9 in this case), how long would it take to guess every possible combination of words? A very, VERY long time
For comparison, under the same scenario, a key with only 4 words would be cracked within 10 Minutes.
Does that mean a key with 4 words is not secure enough? It might depend on the situation.
Casual remote attackers probably won't have access to the ciphertext since they would have to look at your localstorage or guess a gazzillion things over HTTP. I just put a scary disclaimer on the app since I don't want to be holding people's weakly encrypted data.
This software is provided "AS-IS" under the MIT license. For more information see the LICENSE
file.
You should create a separate IAM user in AWS which only has access to the bucket. This is the policy I used for that user. Note that the user does not have the capability to list the bucket contents, only to get and put objects. This is very important for security reasons, otherwise a remote attacker would have a much easier time trying to break the encryption, because they would have easy access to the ciphertext.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::sequentialread-pwm"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::sequentialread-pwm/*"
}
]
}
You will also need to configure CORS on the bucket. This is the CORS configuration I used on the bucket:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>x-amz-content-sha256</AllowedHeader>
<AllowedHeader>x-amz-date</AllowedHeader>
</CORSRule>
</CORSConfiguration>