package com.limegroup.gnutella.simpp; import java.io.UnsupportedEncodingException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.EncodedKeySpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.limewire.security.SignatureVerifier; import org.limewire.util.Base32; public class SimppDataVerifier { private static final Log LOG = LogFactory.getLog(SimppDataVerifier.class); private static final byte SEP = (byte)124; private final String ALGORITHM = "DSA"; private final String DIG_ALG = "SHA1"; private byte[] simppPayload; private byte[] verifiedData; /** * Constructor. Payload contains bytes with the following format: * [Base32 Encoded signature bytes]|[versionnumber|<props in xml format>] */ public SimppDataVerifier(byte[] payload) { this.simppPayload = payload; } public boolean verifySource() { int sepIndex = findSeperator(simppPayload); if(sepIndex < 0) //no separator? this cannot be the real thing. return false; byte[] temp = new byte[sepIndex]; System.arraycopy(simppPayload, 0, temp, 0, sepIndex); String base32 = null; try { base32 = new String(temp, "UTF-8"); } catch (UnsupportedEncodingException uex) { return false; } byte[] signature = Base32.decode(base32); byte[] propsData = new byte[simppPayload.length-1-sepIndex]; System.arraycopy(simppPayload, sepIndex+1, propsData, 0, simppPayload.length-1-sepIndex); PublicKey pk = getPublicKey(); if(pk == null) return false; SignatureVerifier verifier = new SignatureVerifier(propsData, signature, pk, ALGORITHM, DIG_ALG); boolean ret = verifier.verifySignature(); if(ret) verifiedData = propsData; return ret; } /** * @return the verified bytes. Null if we were unable to verify */ public byte[] getVerifiedData() { return verifiedData; } ////////////////////////////helpers///////////////////// private PublicKey getPublicKey() { String base32Enc = "GCBADNZQQIASYBQHFKDERTRYAQATBAQBD4BIDAIA7V7VHAI5OUJCSUW7JKOC53HE473BDN2SHTXUIAGDDY7YBNSREZUUKXKAEJI7WWJ5RVMPVP6F6W5DB5WLTNKWZV4BHOAB2NDP6JTGBN3LTFIKLJE7T7UAI6YQELBE7O5J277LPRQ37A5VPZ6GVCTBKDYE7OB7NU6FD3BQENKUCNNBNEJS6Z27HLRLMHLSV37SEIBRTHORJAA4OAQVACLWAUEPCURQXTFSSK4YFIXLQQF7AWA46UBIDAIA67Q2BBOWTM655S54VNODNOCXXF4ZJL537I5OVAXZK5GAWPIHQJTVCWKXR25NIWKP4ZYQOEEBQC2ESFTREPUEYKAWCO346CJSRTEKNYJ4CZ5IWVD4RUUOBI5ODYV3HJTVSFXKG7YL7IQTKYXR7NRHUAJEHPGKJ4N6VBIZBCNIQPP6CWXFT4DJFC3GL2AHWVJFMQAUYO76Z5ESUA4BQQAAFAMAO23AF7C247RPE4RGGMCU3XQTRVG3ZIKKQUVAS2BKNDBDB3W7L375GYP7ZWZL2RP3WAIBOHZ52G7KT46EAGBUG7DWQNZS4IWC2GDVU4PQ74Q64BJWMK2DZ6G7GYESYHUPBNDOB5PLI2WPF33NIAOXNYQXSEJLTSPUXBMY3RHAQY3TRG6EKQ6CNNZJ2NRVY3RZXLAV3QMVENJIQ"; //3. convert the base32 encoded String into the original bytes byte[] pubKeyBytes = Base32.decode(base32Enc); //4. Make a public key out of it PublicKey ret = null; try { KeyFactory factory = KeyFactory.getInstance(ALGORITHM); EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyBytes); ret = factory.generatePublic(keySpec); } catch(NoSuchAlgorithmException nsax) { LOG.error("no algorithm", nsax); } catch(InvalidKeySpecException iksx) { LOG.error("invalid key", iksx); } return ret; } static int findSeperator(byte[] data) { boolean found = false; int i = 0; for( ; i< data.length; i++) { if(data[i] == SEP) { found = true; break; } } if(found) return i; return -1; } }