mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-05 16:55:05 -05:00
reduce memory usage while parsing multiple keyrings from a stream
This commit is contained in:
parent
aa32c60a0a
commit
ecb2c2c2b1
@ -1,7 +1,6 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||||
import org.spongycastle.bcpg.S2K;
|
|
||||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.openpgp.PGPKeyFlags;
|
import org.spongycastle.openpgp.PGPKeyFlags;
|
||||||
@ -30,12 +29,9 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/** Wrapper around PGPKeyRing class, to be constructed from bytes.
|
/** Wrapper around PGPKeyRing class, to be constructed from bytes.
|
||||||
*
|
*
|
||||||
@ -108,41 +104,84 @@ public class UncachedKeyRing {
|
|||||||
public static UncachedKeyRing decodeFromData(byte[] data)
|
public static UncachedKeyRing decodeFromData(byte[] data)
|
||||||
throws PgpGeneralException, IOException {
|
throws PgpGeneralException, IOException {
|
||||||
|
|
||||||
List<UncachedKeyRing> parsed = fromStream(new ByteArrayInputStream(data));
|
Iterator<UncachedKeyRing> parsed = fromStream(new ByteArrayInputStream(data));
|
||||||
|
|
||||||
if (parsed.isEmpty()) {
|
if ( ! parsed.hasNext()) {
|
||||||
throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
|
throw new PgpGeneralException("Object not recognized as PGPKeyRing!");
|
||||||
}
|
}
|
||||||
if (parsed.size() > 1) {
|
|
||||||
throw new PgpGeneralException(
|
UncachedKeyRing ring = parsed.next();
|
||||||
"Expected single keyring in stream, found " + parsed.size());
|
|
||||||
|
if (parsed.hasNext()) {
|
||||||
|
throw new PgpGeneralException("Expected single keyring in stream, found at least two");
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed.get(0);
|
return ring;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<UncachedKeyRing> fromStream(InputStream stream) throws IOException {
|
public static Iterator<UncachedKeyRing> fromStream(final InputStream stream) throws IOException {
|
||||||
List<UncachedKeyRing> result = new Vector<UncachedKeyRing>();
|
|
||||||
|
|
||||||
while(stream.available() > 0) {
|
return new Iterator<UncachedKeyRing>() {
|
||||||
PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream));
|
|
||||||
|
|
||||||
// go through all objects in this block
|
UncachedKeyRing mNext = null;
|
||||||
Object obj;
|
PGPObjectFactory mObjectFactory = null;
|
||||||
while ((obj = objectFactory.nextObject()) != null) {
|
|
||||||
Log.d(Constants.TAG, "Found class: " + obj.getClass());
|
private void cacheNext() {
|
||||||
if (!(obj instanceof PGPKeyRing)) {
|
if (mNext != null) {
|
||||||
Log.d(Constants.TAG,
|
return;
|
||||||
"Bad object of type " + obj.getClass().getName() + " in stream, proceed with next object...");
|
|
||||||
// skip object
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
result.add(new UncachedKeyRing((PGPKeyRing) obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
try {
|
||||||
|
if (mObjectFactory == null) {
|
||||||
|
if (stream.available() == 0) {
|
||||||
|
// end of stream. that's fine
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mObjectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through all objects in this block
|
||||||
|
Object obj;
|
||||||
|
while ((obj = mObjectFactory.nextObject()) != null) {
|
||||||
|
Log.d(Constants.TAG, "Found class: " + obj.getClass());
|
||||||
|
if (!(obj instanceof PGPKeyRing)) {
|
||||||
|
Log.i(Constants.TAG,
|
||||||
|
"Skipping object of bad type " + obj.getClass().getName() + " in stream");
|
||||||
|
// skip object
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mNext = new UncachedKeyRing((PGPKeyRing) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException while processing stream", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
cacheNext();
|
||||||
|
return mNext != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UncachedKeyRing next() {
|
||||||
|
try {
|
||||||
|
cacheNext();
|
||||||
|
return mNext;
|
||||||
|
} finally {
|
||||||
|
mNext = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void encodeArmored(OutputStream out, String version) throws IOException {
|
public void encodeArmored(OutputStream out, String version) throws IOException {
|
||||||
|
@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
|
|||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ImportKeysListLoader
|
public class ImportKeysListLoader
|
||||||
@ -127,11 +128,12 @@ public class ImportKeysListLoader
|
|||||||
BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
|
BufferedInputStream bufferedInput = new BufferedInputStream(progressIn);
|
||||||
try {
|
try {
|
||||||
// parse all keyrings
|
// parse all keyrings
|
||||||
List<UncachedKeyRing> rings = UncachedKeyRing.fromStream(bufferedInput);
|
Iterator<UncachedKeyRing> it = UncachedKeyRing.fromStream(bufferedInput);
|
||||||
for (UncachedKeyRing key : rings) {
|
while (it.hasNext()) {
|
||||||
ImportKeysListEntry item = new ImportKeysListEntry(getContext(), key);
|
UncachedKeyRing ring = it.next();
|
||||||
|
ImportKeysListEntry item = new ImportKeysListEntry(getContext(), ring);
|
||||||
mData.add(item);
|
mData.add(item);
|
||||||
mParcelableRings.put(item.hashCode(), new ParcelableKeyRing(key.getEncoded()));
|
mParcelableRings.put(item.hashCode(), new ParcelableKeyRing(ring.getEncoded()));
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(Constants.TAG, "IOException on parsing key file! Return NoValidKeysException!", e);
|
Log.e(Constants.TAG, "IOException on parsing key file! Return NoValidKeysException!", e);
|
||||||
|
Loading…
Reference in New Issue
Block a user