All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cryptoregistry.tweet.pepper.KMU Maven / Gradle / Ivy

Go to download

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

import java.util.ArrayList;
import java.util.Base64;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.cryptoregistry.tweet.pbe.PBE;
import com.cryptoregistry.tweet.pbe.PBEParams;
import com.cryptoregistry.tweet.pepper.key.BoxingKeyContents;
import com.cryptoregistry.tweet.pepper.key.BoxingKeyForPublication;
import com.cryptoregistry.tweet.pepper.key.SigningKeyContents;
import com.cryptoregistry.tweet.salt.pqc.NHKeyForPublication;
import com.cryptoregistry.tweet.url.BijectiveEncoder;

/**
 * A KMU or "KeyMaterialUnit" is a set which can contain keys, signatures, and associated arbitrary data.
 * 
 * When built for public use it has a unique transaction ID for use in transactions and an administrative 
 * contact email for issues
 * 
 * @author Dave
 *
 */
public class KMU {

	public static final String transactionVersion = "TweetPepper\u00AE Transaction Format 1.0";
	public static final String confidentialKeyVersion = "TweetPepper\u00AE Keystore Format 1.0";
	
	public final String version;
	public final String kmuHandle; // essentially a transaction handle, UUID that ends in "-T"
	public final String adminEmail; // immediate contact point for questions, failures, etc
	
	public final Map map; // keys are distinguished-names to the blocks
	public Map aliases;
	
	public KMU() {
		super();
		this.version = confidentialKeyVersion;
		this.kmuHandle = null;
		this.adminEmail = null;
		this.map = new LinkedHashMap();
	}
	
	public KMU(Block...blocks){
		this();
		for(Block b: blocks){
			this.map.put(b.name,b);
		}
	}
	
	public KMU(String adminEmail) {
		super();
		this.version = transactionVersion;
		BijectiveEncoder enc= new BijectiveEncoder();
		this.kmuHandle = enc.encode(UUID.randomUUID())+"-"+BlockType.T;
		this.adminEmail = adminEmail;
		this.map = new LinkedHashMap();
	}

	public KMU(String kmuHandle, String adminEmail) {
		super();
		this.version = transactionVersion;
		this.kmuHandle = kmuHandle;
		this.adminEmail = adminEmail;
		this.map = new LinkedHashMap();
	}
	
	public KMU addBlock(Block block){
		map.put(block.toString(), block);
		return this;
	}
	
	public KMU addBlocks(List blocks){
		for(Block block: blocks) map.put(block.toString(), block);
		return this;
	}
	
	// TODO
	public void addAlias(String alias, String name){
		if(aliases == null){
			
		}
	}
	
	/**
	 * 

Any blocks of type -U will be altered:

* *
    *
  1. S will be encrypted and changed to X
  2. *
  3. the distinguished name will be changed to -X
  4. *
* *

If the password value is forgotten there is no way to re-set it, and it cannot be set to null

* *

this method takes some time and CPU, which is intentional. SCrypt is a strong KDF.

* * @param password */ public void protectKeyBlocks(char [] password) { List list = new ArrayList(); for(String s: map.keySet()){ Block b = map.get(s); if(b.name.endsWith("-U")){ String base64UnsecureKey = b.get("S"); PBEParams params = new TweetPepper().createPBEParams(); PBE pbe = new PBE(params); String enc = pbe.protect(password, Base64.getUrlDecoder().decode(base64UnsecureKey)); b.remove("S"); b.put("X", enc); list.add(b); } } for(Block b: list){ map.remove(b.name); b.name = b.name.substring(0,b.name.length()-2)+"-X"; map.put(b.name, b); } } /** * Open (unencrypt) blocks of type -X if found in the KMU. Currently this expects all protected keys to * have the same password. * * @param password */ public void openKeyBlocks(char [] password) { for(String s: map.keySet()){ Block b = map.get(s); if(b.name.endsWith("-X")){ String base64SecureKey = b.get("X"); PBE pbe = new PBE(); byte [] confidentialKey = pbe.unprotect(password, base64SecureKey); b.remove("X"); b.put("S", Base64.getUrlEncoder().encodeToString(confidentialKey)); b.name = b.name.substring(0,b.name.length()-2)+"-U"; } } } /** * Given a block name, add (or update an existing) key and value * * @param blockname * @param key * @param value */ public void updateBlock(String blockname, String key, String value){ for(String dname: map.keySet()){ if(blockname.equals(dname)){ Block item = map.get(dname); item.put(key, value); return; } } } public void removeBlockItem(String blockname, String key){ for(String dname: map.keySet()){ if(blockname.equals(dname)){ Block item = map.get(dname); item.remove(key); return; } } } /** * Return the first appropriate block found as a rehydrated key or null if none found * * @return the reydrated key if found */ public SigningKeyContents getSigningKey(){ for(String s: map.keySet()){ Block b = map.get(s); if(b.name.endsWith("-U")){ if(b.containsKey("KeyUsage")&&b.get("KeyUsage").equals("Signing")) { // found a signing key return new SigningKeyContents(b); } } } return null; } /** * Return the first appropriate block found as a rehydrated key or null if none found * * @return the reydrated key if found */ public BoxingKeyContents getBoxingKey(){ for(String s: map.keySet()){ Block b = map.get(s); if(b.name.endsWith("-U")){ if(b.containsKey("KeyUsage")&&b.get("KeyUsage").equals("Boxing")) { // found a signing key return new BoxingKeyContents(b); } } } return null; } public BoxingKeyForPublication getBoxingPubKey(){ for(String s: map.keySet()){ Block b = map.get(s); if(b.name.endsWith("-P")){ if(b.containsKey("KeyUsage")&&b.get("KeyUsage").equals("Boxing")) { // found a signing key return new BoxingKeyForPublication(b); } } } return null; } public NHKeyForPublication getNewHopePubKey(){ for(String s: map.keySet()){ Block b = map.get(s); if(b.name.endsWith("-P")){ if(b.containsKey("KeyUsage")&&b.get("KeyUsage").equals("Agreement")) { // found an agreement key return new NHKeyForPublication(b); } } } return null; } /** * merge some other KMU contents into this one (return this). Notices if a key is * duplicate and does not take it on board * * @param kmu * @return */ public KMU mergeBlocks(KMU...kmus){ for(KMU item: kmus){ Iterator iter = item.map.keySet().iterator(); while(iter.hasNext()){ String key = iter.next(); if(this.map.containsKey(key))continue; else{ this.map.put(key, item.map.get(key)); } } } return this; } /** * Return the first block of this type * * @param type * @return */ public Block findBlock(BlockType type){ for(String s: map.keySet()){ Block b = map.get(s); if(type.equals(b.getBlockType())) return b; } return null; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((adminEmail == null) ? 0 : adminEmail.hashCode()); result = prime * result + ((aliases == null) ? 0 : aliases.hashCode()); result = prime * result + ((kmuHandle == null) ? 0 : kmuHandle.hashCode()); result = prime * result + ((map == null) ? 0 : map.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; KMU other = (KMU) obj; if (adminEmail == null) { if (other.adminEmail != null) return false; } else if (!adminEmail.equals(other.adminEmail)) return false; if (aliases == null) { if (other.aliases != null) return false; } else if (!aliases.equals(other.aliases)) return false; if (kmuHandle == null) { if (other.kmuHandle != null) return false; } else if (!kmuHandle.equals(other.kmuHandle)) return false; if (map == null) { if (other.map != null) return false; } else if (!map.equals(other.map)) return false; if (version == null) { if (other.version != null) return false; } else if (!version.equals(other.version)) return false; return true; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy