
com.cryptoregistry.tweet.pbe.PBE Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tweetpepper Show documentation
Show all versions of tweetpepper Show documentation
Built on the nucleus of TweetNaCl, TweetPepper provides contemporary key formats, key protection using SCrypt/SecretBox, digital signature support scheme featuring CubeHash, key encapsulation using Salsa20, and other useful features you probably want anyway.
The newest version!
/*
Copyright 2016, David R. Smith, All Rights Reserved
This file is part of TweetPepper.
TweetPepper is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
TweetPepper is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with TweetPepper. If not, see .
*/
package com.cryptoregistry.tweet.pbe;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Base64;
import com.cryptoregistry.tweet.salt.TweetNaCl;
import com.lambdaworks.crypto.SCrypt;
/**
* Simple to use but powerful PBE based on scrypt and secretbox.
*
* @author Dave
*
*/
public class PBE {
private final PBEParams params;
/**
* Used with protect()
*
* @param params
*/
public PBE(PBEParams params) {
super();
this.params = params;
if(this.params.N == 0 || this.params.r == 0 || this.params.p == 0) throw new RuntimeException("Invalid SCrypt predicates");
}
/**
* Used with unprotect()
*/
public PBE() {
super();
this.params = null;
}
/**
* Protect some bytes using our SCrypt/SecretBox algorithm. password is zeroed out as a side-effect.
*
* @param password
* @param confidentialBytes
* @return a String, the Base64url encoded bytes prepended with a header containing the parameters
*
*/
public String protect(char[] password, byte[] confidentialBytes) {
if (params == null) throw new RuntimeException("Need to set params in constructor first before this call.");
if (password == null) throw new RuntimeException("Password cannot be null.");
TweetNaCl salt = new TweetNaCl();
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream doubt = new DataOutputStream(out);
try {
// the pbe key
byte[] derived = SCrypt.scrypt(toBytes(password),
params.scryptSalt, params.N, params.r, params.p, 32);
doubt.writeByte((byte)'t');
doubt.writeByte((byte)'p');
doubt.writeShort(params.N); // 2 bytes
doubt.writeShort(params.r); // 2 bytes
doubt.writeShort(params.p); // 2 bytes
doubt.write(params.scryptSalt); // 16 bytes
doubt.write(params.nonce); // 24 bytes
byte[] enc = salt.secretbox(confidentialBytes, params.nonce,derived);
doubt.write(enc); // variable length?
doubt.flush();
String encoded = Base64.getUrlEncoder().encodeToString(out.toByteArray());
cleanup(password); // clear password
return encoded;
} catch (Exception x) {
throw new RuntimeException(x);
}
}
/**
* decrypt our protected bytes and return them. password is zeroed out as a side effect of this method
*
* @param password
* @param protectedString
* @return the confidential bytes
*/
public byte [] unprotect(char[] password, String protectedString) {
TweetNaCl salt = new TweetNaCl();
try {
byte[] packed = Base64.getUrlDecoder().decode(protectedString);
ByteArrayInputStream bin = new ByteArrayInputStream(packed);
DataInputStream in = new DataInputStream(bin);
char first = (char)in.readByte();
char second = (char)in.readByte();
if(!(first == 't' && second == 'p')){
throw new RuntimeException("Magic does not match: "+first+""+second+"input is not encoded as expected");
}
int N = in.readShort();
int r = in.readShort();
int p = in.readShort();
byte [] scryptSalt = new byte[16];
in.readFully(scryptSalt);
byte [] nonce = new byte[TweetNaCl.BOX_NONCE_BYTES];
in.readFully(nonce);
byte [] enc = new byte[packed.length - (2+2+2+2+16+TweetNaCl.BOX_NONCE_BYTES)];
in.readFully(enc);
// the pbe key
byte[] derived = SCrypt.scrypt(toBytes(password), scryptSalt, N, r, p, 32);
// unboxing
byte [] confidential = salt.secretbox_open(enc, nonce, derived);
cleanup(password);
return confidential;
} catch (Exception x) {
throw new RuntimeException(x);
}
}
private void cleanup(char[] array) {
Arrays.fill(array, '\u0000');
}
private byte[] toBytes(char[] password) {
CharBuffer charBuffer = CharBuffer.wrap(password);
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
byteBuffer.position(), byteBuffer.limit());
Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
return bytes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy