001package co.codewizards.cloudstore.updater; 002 003import static co.codewizards.cloudstore.core.util.Util.*; 004 005import java.io.BufferedInputStream; 006import java.io.File; 007import java.io.FileInputStream; 008import java.io.InputStream; 009 010import org.bouncycastle.jce.provider.BouncyCastleProvider; 011import org.bouncycastle.openpgp.PGPObjectFactory; 012import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; 013import org.bouncycastle.openpgp.PGPSignature; 014import org.bouncycastle.openpgp.PGPSignatureList; 015import org.bouncycastle.openpgp.PGPUtil; 016 017public class PGPVerifier { 018 private PGPPublicKeyRingCollection publicKeyRingWithTrustedKeys; 019 private final BouncyCastleProvider provider = new BouncyCastleProvider(); 020 021 /** 022 * Verify the specified {@code file}. 023 * @param file the file to be verified. Must not be <code>null</code>. There must be a second file 024 * with the same name and the additional suffix ".sig" next to this file (in the same directory). 025 * This secondary file is a so-called detached signature. 026 * @throws PGPVerifyException if the given {@code file} could not be verified successfully. Either 027 * there is no detached-signature-file, or its signature is broken or its signature does not match 028 * any of the {@linkplain #getPublicKeyRingWithTrustedKeys() trusted keys}. 029 */ 030 public void verify(final File file, final File signatureFile) throws PGPVerifyException { 031 assertNotNull("file", file); 032 assertNotNull("signatureFile", signatureFile); 033 034 final PGPSignatureList sl = readSignatureFile(signatureFile); 035 final PGPPublicKeyRingCollection publicKeyRing = getPublicKeyRingWithTrustedKeys(); 036 037 for (int index = 0; index < sl.size(); ++index) { 038 try { 039 final PGPSignature signature = sl.get(index); 040 signature.initVerify(publicKeyRing.getPublicKey(signature.getKeyID()), provider); 041 042 final InputStream contentIn = new FileInputStream(file); 043 try { 044 final byte[] buf = new byte[16 * 1024]; 045 int len; 046 while (0 <= (len = contentIn.read(buf))) { 047 if (len > 0) 048 signature.update(buf, 0, len); 049 } 050 } finally { 051 contentIn.close(); 052 } 053 054 if (signature.verify()) 055 return; 056 057 } catch (Exception e) { 058 throw new PGPVerifyException(file.getAbsolutePath() + ": " + e, e); 059 } 060 } 061 throw new PGPVerifyException(file.getAbsolutePath()); 062 } 063 064 private PGPPublicKeyRingCollection getPublicKeyRingWithTrustedKeys() { 065 try { 066 PGPPublicKeyRingCollection ring = publicKeyRingWithTrustedKeys; 067 if (ring == null) { 068 // Currently only one single trusted key ;-) 069 final InputStream publicKeyIn = new BufferedInputStream(PGPVerifier.class.getResourceAsStream("/0x4AB0FBC1.asc")); 070 try { 071 ring = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(publicKeyIn)); 072 } finally { 073 publicKeyIn.close(); 074 } 075 publicKeyRingWithTrustedKeys = ring; 076 } 077 return ring; 078 } catch (RuntimeException x) { 079 throw x; 080 } catch (Exception x) { 081 throw new RuntimeException(x); 082 } 083 } 084 085 private PGPSignatureList readSignatureFile(final File signatureFile) throws PGPVerifyException { 086 assertNotNull("signatureFile", signatureFile); 087 if (!signatureFile.isFile() || !signatureFile.canRead()) 088 throw new PGPVerifyException("The signature-file does not exist or is not readable: " + signatureFile.getAbsolutePath()); 089 090 try { 091 InputStream in = new BufferedInputStream(new FileInputStream(signatureFile)); 092 try { 093 final PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(in)); 094 final PGPSignatureList sl = (PGPSignatureList) objectFactory.nextObject(); 095 return sl; 096 } finally { 097 in.close(); 098 } 099 } catch (Exception e) { 100 throw new PGPVerifyException(signatureFile.getAbsolutePath() + ": " + e, e); 101 } 102 } 103}