jruby-pgp 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +10 -3
- data/Rakefile +3 -0
- data/ext/org/sgonyea/pgp/Decryptor.java +147 -0
- data/ext/org/sgonyea/pgp/Encryptor.java +13 -13
- data/lib/pgp.rb +3 -2
- data/lib/pgp/decryptor.rb +1 -53
- data/lib/pgp/encryptor.rb +42 -2
- data/lib/pgp/ruby_decryptor.rb +58 -0
- data/lib/pgp/version.rb +1 -1
- data/spec/lib/pgp/decryptor_spec.rb +24 -0
- data/spec/lib/pgp/encryptor_spec.rb +61 -7
- data/spec/support/fixtures/unencrypted_file.txt +1 -0
- data/spec/support/fixtures/unencrypted_file.txt.asc +19 -0
- metadata +117 -94
- data/ext/org/sgonyea/pgp/PGP.java +0 -49
data/README.md
CHANGED
@@ -16,18 +16,25 @@ Or install it yourself as:
|
|
16
16
|
|
17
17
|
$ gem install jruby-pgp
|
18
18
|
|
19
|
-
##
|
19
|
+
## Notes
|
20
20
|
|
21
21
|
This gem currently features everything I need and nothing I don't. Pull requests are very much welcome;
|
22
22
|
feature requests will be considered.
|
23
23
|
|
24
24
|
The general goal is to provide fast, non-terrible wrappers around the Bouncy Castle PGP APIs. Bare-metal
|
25
25
|
JRuby code will then plug into those wrappers, to minimize memory bloat. Directly hooking JRuby into the
|
26
|
-
BC PGP APIs is certainly possible, but they are a
|
27
|
-
|
26
|
+
BC PGP APIs is certainly possible, but they are a pile of rocks. Using these APIs from JRuby can yield
|
27
|
+
some unwanted bloat, especially when you're resource constrained:
|
28
28
|
|
29
29
|
[Example using BC PGP directly from JRuby](https://gist.github.com/1954648)
|
30
30
|
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
For usage examples, see the below test files:
|
34
|
+
|
35
|
+
Encryption: spec/lib/pgp/encryptor_spec.rb
|
36
|
+
Decryption: spec/lib/pgp/decryptor_spec.rb
|
37
|
+
|
31
38
|
## Contributing
|
32
39
|
|
33
40
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -12,6 +12,8 @@ Rake::JavaExtensionTask.new('jruby-pgp') do |ext|
|
|
12
12
|
ext.classpath = jars.map { |x| File.expand_path x }.join ':'
|
13
13
|
end
|
14
14
|
|
15
|
+
RSpec::Core::RakeTask.new
|
16
|
+
|
15
17
|
RSpec::Core::RakeTask.new(:rcov) do |task|
|
16
18
|
task.rcov = true
|
17
19
|
end
|
@@ -19,3 +21,4 @@ end
|
|
19
21
|
task :default => %w(compile spec)
|
20
22
|
|
21
23
|
task :build => :compile
|
24
|
+
task :spec => :compile
|
@@ -0,0 +1,147 @@
|
|
1
|
+
/**
|
2
|
+
* Much of this code was stolen from this Stack Overflow post:
|
3
|
+
* http://stackoverflow.com/questions/3939447/how-to-encrypt-a-string-stream-with-bouncycastle-pgp-without-starting-with-a-fil
|
4
|
+
*
|
5
|
+
* In addition to the java versions of this lump of code, that have been floating around on the internet:
|
6
|
+
* https://gist.github.com/1954648
|
7
|
+
*
|
8
|
+
* Thanks to everyone who has posted on the topic of Bouncy Castle's PGP Library.
|
9
|
+
*/
|
10
|
+
|
11
|
+
package org.sgonyea.pgp;
|
12
|
+
|
13
|
+
import java.io.ByteArrayInputStream;
|
14
|
+
import java.io.ByteArrayOutputStream;
|
15
|
+
import java.io.File;
|
16
|
+
import java.io.FileInputStream;
|
17
|
+
import java.io.FileOutputStream;
|
18
|
+
import java.io.IOException;
|
19
|
+
import java.io.InputStream;
|
20
|
+
import java.io.OutputStream;
|
21
|
+
import java.security.NoSuchProviderException;
|
22
|
+
import java.security.SecureRandom;
|
23
|
+
import java.security.Security;
|
24
|
+
import java.util.Date;
|
25
|
+
import java.util.Iterator;
|
26
|
+
|
27
|
+
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
28
|
+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
29
|
+
import org.bouncycastle.openpgp.PGPCompressedData;
|
30
|
+
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
31
|
+
import org.bouncycastle.openpgp.PGPEncryptedData;
|
32
|
+
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
33
|
+
import org.bouncycastle.openpgp.PGPEncryptedDataList;
|
34
|
+
import org.bouncycastle.openpgp.PGPException;
|
35
|
+
import org.bouncycastle.openpgp.PGPLiteralData;
|
36
|
+
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
|
37
|
+
import org.bouncycastle.openpgp.PGPObjectFactory;
|
38
|
+
import org.bouncycastle.openpgp.PGPPrivateKey;
|
39
|
+
import org.bouncycastle.openpgp.PGPPublicKey;
|
40
|
+
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
|
41
|
+
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
42
|
+
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
43
|
+
import org.bouncycastle.openpgp.PGPSecretKey;
|
44
|
+
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
45
|
+
import org.bouncycastle.openpgp.PGPUtil;
|
46
|
+
|
47
|
+
public class Decryptor {
|
48
|
+
|
49
|
+
private PGPSecretKeyRingCollection _privateKeys;
|
50
|
+
|
51
|
+
public Decryptor() { }
|
52
|
+
public Decryptor(PGPSecretKeyRingCollection privateKeys) {
|
53
|
+
setPrivateKeys(privateKeys);
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Accessor and Attribute Helper Methods
|
58
|
+
**/
|
59
|
+
public PGPSecretKeyRingCollection getPrivateKeys() {
|
60
|
+
return _privateKeys;
|
61
|
+
}
|
62
|
+
|
63
|
+
public void setPrivateKeys(PGPSecretKeyRingCollection privateKeys) {
|
64
|
+
_privateKeys = privateKeys;
|
65
|
+
}
|
66
|
+
|
67
|
+
public PGPPrivateKey findPrivateKey(long keyID)
|
68
|
+
throws PGPException, NoSuchProviderException {
|
69
|
+
PGPSecretKey pgpSecKey = getPrivateKeys().getSecretKey(keyID);
|
70
|
+
|
71
|
+
if (pgpSecKey == null)
|
72
|
+
return null;
|
73
|
+
|
74
|
+
// null = the password. We won't need this for now.
|
75
|
+
return pgpSecKey.extractPrivateKey(null, "BC");
|
76
|
+
}
|
77
|
+
|
78
|
+
/** End Accessor Methods **/
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Decryption Instance Methods
|
82
|
+
**/
|
83
|
+
|
84
|
+
public byte[] decryptBytes(byte[] encryptedBytes)
|
85
|
+
throws IOException, PGPException, NoSuchProviderException {
|
86
|
+
InputStream stream = new ByteArrayInputStream(encryptedBytes);
|
87
|
+
return decryptStream(stream);
|
88
|
+
}
|
89
|
+
|
90
|
+
public byte[] decryptStream(InputStream encryptedStream)
|
91
|
+
throws IOException, PGPException, NoSuchProviderException {
|
92
|
+
|
93
|
+
InputStream decoderStream = PGPUtil.getDecoderStream(encryptedStream);
|
94
|
+
|
95
|
+
PGPObjectFactory pgpF = new PGPObjectFactory(decoderStream);
|
96
|
+
PGPEncryptedDataList encryptedData = null;
|
97
|
+
Object encryptedObj = pgpF.nextObject();
|
98
|
+
Iterator encryptedDataIterator;
|
99
|
+
PGPPublicKeyEncryptedData publicKeyData = null;
|
100
|
+
PGPPrivateKey privateKey = null;
|
101
|
+
InputStream decryptedDataStream;
|
102
|
+
PGPObjectFactory pgpFactory;
|
103
|
+
PGPCompressedData compressedData;
|
104
|
+
PGPLiteralData literallyTheRealFuckingData;
|
105
|
+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
106
|
+
byte[] returnBytes;
|
107
|
+
|
108
|
+
// the first object might be a PGP marker packet.
|
109
|
+
if (encryptedObj instanceof PGPEncryptedDataList)
|
110
|
+
encryptedData = (PGPEncryptedDataList) encryptedObj;
|
111
|
+
else
|
112
|
+
encryptedData = (PGPEncryptedDataList) pgpF.nextObject();
|
113
|
+
|
114
|
+
encryptedDataIterator = encryptedData.getEncryptedDataObjects();
|
115
|
+
|
116
|
+
while (privateKey == null && encryptedDataIterator.hasNext()) {
|
117
|
+
publicKeyData = (PGPPublicKeyEncryptedData) encryptedDataIterator.next();
|
118
|
+
|
119
|
+
privateKey = findPrivateKey(publicKeyData.getKeyID());
|
120
|
+
}
|
121
|
+
|
122
|
+
if (privateKey == null)
|
123
|
+
throw new IllegalArgumentException("secret key for message not found.");
|
124
|
+
|
125
|
+
decryptedDataStream = publicKeyData.getDataStream(privateKey, "BC");
|
126
|
+
|
127
|
+
pgpFactory = new PGPObjectFactory(decryptedDataStream);
|
128
|
+
|
129
|
+
compressedData = (PGPCompressedData) pgpFactory.nextObject();
|
130
|
+
|
131
|
+
pgpFactory = new PGPObjectFactory(compressedData.getDataStream());
|
132
|
+
|
133
|
+
literallyTheRealFuckingData = (PGPLiteralData) pgpFactory.nextObject();
|
134
|
+
|
135
|
+
decryptedDataStream = literallyTheRealFuckingData.getInputStream();
|
136
|
+
|
137
|
+
int ch;
|
138
|
+
while ((ch = decryptedDataStream.read()) >= 0)
|
139
|
+
outputStream.write(ch);
|
140
|
+
|
141
|
+
returnBytes = outputStream.toByteArray();
|
142
|
+
outputStream.close();
|
143
|
+
|
144
|
+
return returnBytes;
|
145
|
+
}
|
146
|
+
|
147
|
+
}
|
@@ -6,7 +6,7 @@
|
|
6
6
|
* https://gist.github.com/1954648
|
7
7
|
*
|
8
8
|
* Thanks to everyone who has posted on the topic of Bouncy Castle's PGP Library.
|
9
|
-
|
9
|
+
**/
|
10
10
|
|
11
11
|
package org.sgonyea.pgp;
|
12
12
|
|
@@ -87,7 +87,7 @@ public class Encryptor {
|
|
87
87
|
|
88
88
|
/**
|
89
89
|
* Accessor and Attribute Helper Methods
|
90
|
-
|
90
|
+
**/
|
91
91
|
|
92
92
|
/* integrityCheck */
|
93
93
|
public void setIntegrityCheck(boolean integrityCheck) {
|
@@ -187,7 +187,7 @@ public class Encryptor {
|
|
187
187
|
|
188
188
|
/**
|
189
189
|
* @see org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags
|
190
|
-
|
190
|
+
**/
|
191
191
|
public void setAlgorithm(int algorithm) {
|
192
192
|
_algorithm = algorithm;
|
193
193
|
}
|
@@ -197,32 +197,32 @@ public class Encryptor {
|
|
197
197
|
|
198
198
|
/**
|
199
199
|
* Encryption Class / Static Methods
|
200
|
-
|
200
|
+
**/
|
201
201
|
|
202
202
|
/**
|
203
|
-
* This method preserves the much of the
|
204
|
-
|
205
|
-
public static byte[]
|
203
|
+
* This method preserves the much of the stolen API, so that you can just call the class method should you need to.
|
204
|
+
**/
|
205
|
+
public static byte[] encryptBytes(byte[] clearData, List<PGPPublicKey> publicKeys, String fileName, boolean withIntegrityCheck, boolean armor)
|
206
206
|
throws IOException, PGPException, NoSuchProviderException {
|
207
207
|
Encryptor encryptor = new Encryptor(publicKeys);
|
208
208
|
|
209
|
-
return encryptor.
|
209
|
+
return encryptor.encryptBytes(clearData, fileName);
|
210
210
|
}
|
211
211
|
|
212
212
|
|
213
213
|
/**
|
214
214
|
* Encryption Instance Methods
|
215
|
-
|
216
|
-
public byte[]
|
215
|
+
**/
|
216
|
+
public byte[] encryptBytes(byte[] clearData, String fileName)
|
217
217
|
throws IOException, PGPException, NoSuchProviderException {
|
218
|
-
return
|
218
|
+
return encryptBytes(clearData, fileName, new Date());
|
219
219
|
}
|
220
220
|
|
221
221
|
/**
|
222
222
|
* Allows you to override the modificationTime. This method was split off
|
223
223
|
* for mock-free testing of encrypted output.
|
224
|
-
|
225
|
-
public byte[]
|
224
|
+
**/
|
225
|
+
public byte[] encryptBytes(byte[] clearData, String fileName, Date modificationTime)
|
226
226
|
throws IOException, PGPException, NoSuchProviderException {
|
227
227
|
if (fileName == null)
|
228
228
|
fileName = PGPLiteralData.CONSOLE;
|
data/lib/pgp.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'java'
|
2
|
-
require 'pgp/jars/bcprov-jdk15on-147.jar'
|
2
|
+
require 'pgp/jars/bcprov-jdk15on-147.jar' if JRUBY_VERSION < '1.7'
|
3
3
|
require 'pgp/jars/bcpg-jdk15on-147.jar'
|
4
4
|
require 'pgp/jruby-pgp.jar'
|
5
5
|
|
@@ -8,7 +8,8 @@ require 'pgp/encryptor'
|
|
8
8
|
require 'pgp/private_key'
|
9
9
|
|
10
10
|
module PGP
|
11
|
-
autoload :VERSION,
|
11
|
+
autoload :VERSION, 'pgp/version'
|
12
|
+
autoload :RubyDecryptor, 'pgp/ruby_decryptor'
|
12
13
|
|
13
14
|
BC_Provider_Code = "BC"
|
14
15
|
|
data/lib/pgp/decryptor.rb
CHANGED
@@ -1,58 +1,6 @@
|
|
1
1
|
module PGP
|
2
|
-
class Decryptor
|
2
|
+
class Decryptor < org.sgonyea.pgp.Decryptor
|
3
3
|
include_package "org.bouncycastle.openpgp"
|
4
4
|
|
5
|
-
java_import 'java.io.ByteArrayOutputStream'
|
6
|
-
|
7
|
-
def self.decrypt(encrypted_text, private_key_file)
|
8
|
-
bytes = PGP.string_to_bais(encrypted_text)
|
9
|
-
dec_s = PGPUtil.get_decoder_stream(bytes)
|
10
|
-
pgp_f = PGPObjectFactory.new(dec_s)
|
11
|
-
|
12
|
-
enc_data = pgp_f.next_object
|
13
|
-
enc_data = pgp_f.next_object unless PGPEncryptedDataList === enc_data
|
14
|
-
|
15
|
-
data_enumerator = enc_data.get_encrypted_data_objects
|
16
|
-
|
17
|
-
sec_key = nil
|
18
|
-
pbe = nil
|
19
|
-
|
20
|
-
data_enumerator.each do |pubkey_enc_data|
|
21
|
-
pbe = pubkey_enc_data
|
22
|
-
key_id = pubkey_enc_data.get_key_id
|
23
|
-
sec_key = PrivateKey.from_file(private_key_file, key_id)
|
24
|
-
|
25
|
-
if sec_key.nil?
|
26
|
-
# @todo: Should we notify Airbrake?
|
27
|
-
Ace.logger.debug "This may be cause for concern. The data being decrypted has a key_id of '#{key_id}', which can not be found in the private key file '#{CE_Private_Key}'."
|
28
|
-
else
|
29
|
-
break
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
clear = pbe.get_data_stream(sec_key, BC_Provider_Code)
|
34
|
-
|
35
|
-
plain_fact = PGPObjectFactory.new(clear)
|
36
|
-
|
37
|
-
message = plain_fact.next_object
|
38
|
-
|
39
|
-
if(PGPCompressedData === message)
|
40
|
-
pgp_fact = PGPObjectFactory.new(message.get_data_stream)
|
41
|
-
message = pgp_fact.next_object
|
42
|
-
end
|
43
|
-
|
44
|
-
baos = ByteArrayOutputStream.new
|
45
|
-
|
46
|
-
if(PGPLiteralData === message)
|
47
|
-
unc = message.get_input_stream
|
48
|
-
while((ch = unc.read) >= 0)
|
49
|
-
baos.write(ch)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
baos.to_string
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
5
|
end
|
58
6
|
end
|
data/lib/pgp/encryptor.rb
CHANGED
@@ -2,9 +2,43 @@ module PGP
|
|
2
2
|
class Encryptor < org.sgonyea.pgp.Encryptor
|
3
3
|
include_package "org.bouncycastle.openpgp"
|
4
4
|
|
5
|
+
def initialize(key_string=nil)
|
6
|
+
super()
|
7
|
+
add_keys(key_string) if key_string
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_keys(key_string)
|
11
|
+
key_enumerator = keyring_from_string(key_string).get_key_rings
|
12
|
+
add_keys_from_enumerator(key_enumerator)
|
13
|
+
end
|
14
|
+
|
5
15
|
def add_keys_from_file(filename)
|
6
16
|
key_enumerator = keyring_from_file(filename).get_key_rings
|
17
|
+
add_keys_from_enumerator(key_enumerator)
|
18
|
+
end
|
19
|
+
|
20
|
+
def encrypt(cleartext, filename=nil)
|
21
|
+
name = filename.to_s if filename
|
22
|
+
bytes = cleartext.to_java_bytes
|
23
|
+
|
24
|
+
_encrypt(bytes, name)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @todo: Create an encryptStream method and pass it the file handle
|
28
|
+
def encrypt_file(file_path)
|
29
|
+
name = File.basename(file_path)
|
30
|
+
bytes = File.read(file_path).to_java_bytes
|
7
31
|
|
32
|
+
_encrypt(bytes, name)
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
def _encrypt(bytes, name)
|
37
|
+
encrypted_bytes = encrypt_bytes(bytes, name)
|
38
|
+
encrypted_string = String.from_java_bytes(encrypted_bytes)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_keys_from_enumerator(key_enumerator)
|
8
42
|
key_enumerator.each do |pk_ring|
|
9
43
|
pk_enumerator = pk_ring.get_public_keys
|
10
44
|
|
@@ -16,11 +50,17 @@ module PGP
|
|
16
50
|
end
|
17
51
|
end
|
18
52
|
|
19
|
-
protected
|
20
53
|
def keyring_from_file(filename)
|
21
54
|
file = File.open(filename)
|
22
|
-
|
55
|
+
keyring_from_stream(file.to_inputstream)
|
56
|
+
end
|
57
|
+
|
58
|
+
def keyring_from_string(key_string)
|
59
|
+
keyring_from_stream PGP.string_to_bais(key_string)
|
60
|
+
end
|
23
61
|
|
62
|
+
def keyring_from_stream(stream)
|
63
|
+
yafs = PGPUtil.get_decoder_stream(stream)
|
24
64
|
PGPPublicKeyRingCollection.new(yafs)
|
25
65
|
end
|
26
66
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module PGP
|
2
|
+
class RubyDecryptor
|
3
|
+
include_package "org.bouncycastle.openpgp"
|
4
|
+
|
5
|
+
java_import 'java.io.ByteArrayOutputStream'
|
6
|
+
|
7
|
+
def self.decrypt(encrypted_text, private_key_file)
|
8
|
+
bytes = PGP.string_to_bais(encrypted_text)
|
9
|
+
dec_s = PGPUtil.get_decoder_stream(bytes)
|
10
|
+
pgp_f = PGPObjectFactory.new(dec_s)
|
11
|
+
|
12
|
+
enc_data = pgp_f.next_object
|
13
|
+
enc_data = pgp_f.next_object unless PGPEncryptedDataList === enc_data
|
14
|
+
|
15
|
+
data_enumerator = enc_data.get_encrypted_data_objects
|
16
|
+
|
17
|
+
sec_key = nil
|
18
|
+
pbe = nil
|
19
|
+
|
20
|
+
data_enumerator.each do |pubkey_enc_data|
|
21
|
+
pbe = pubkey_enc_data
|
22
|
+
key_id = pubkey_enc_data.get_key_id
|
23
|
+
sec_key = PrivateKey.from_file(private_key_file, key_id)
|
24
|
+
|
25
|
+
if sec_key.nil?
|
26
|
+
# @todo: Should we notify Airbrake?
|
27
|
+
Ace.logger.debug "This may be cause for concern. The data being decrypted has a key_id of '#{key_id}', which can not be found in the private key file '#{CE_Private_Key}'."
|
28
|
+
else
|
29
|
+
break
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
clear = pbe.get_data_stream(sec_key, BC_Provider_Code)
|
34
|
+
|
35
|
+
plain_fact = PGPObjectFactory.new(clear)
|
36
|
+
|
37
|
+
message = plain_fact.next_object
|
38
|
+
|
39
|
+
if(PGPCompressedData === message)
|
40
|
+
pgp_fact = PGPObjectFactory.new(message.get_data_stream)
|
41
|
+
message = pgp_fact.next_object
|
42
|
+
end
|
43
|
+
|
44
|
+
baos = ByteArrayOutputStream.new
|
45
|
+
|
46
|
+
if(PGPLiteralData === message)
|
47
|
+
unc = message.get_input_stream
|
48
|
+
while((ch = unc.read) >= 0)
|
49
|
+
baos.write(ch)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
baos.to_string
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/pgp/version.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PGP::Decryptor do
|
4
|
+
let(:private_key_path) { Fixtures_Path.join('private_key.asc').to_s }
|
5
|
+
let(:public_key_path) { Fixtures_Path.join('public_key.asc').to_s }
|
6
|
+
|
7
|
+
let(:decryptor) { PGP::Decryptor.new }
|
8
|
+
|
9
|
+
let(:encrypted_file) { Fixtures_Path.join('unencrypted_file.txt.asc') }
|
10
|
+
let(:encrypted_text) { File.read(encrypted_file) }
|
11
|
+
let(:file_path) { Fixtures_Path.join('unencrypted_file.txt') }
|
12
|
+
let(:unencrypted_text) { File.read(file_path) }
|
13
|
+
|
14
|
+
describe '#decrypt' do
|
15
|
+
before {
|
16
|
+
keyring = PGP::PrivateKey.send(:keyring_from_file, private_key_path)
|
17
|
+
decryptor.private_keys = keyring
|
18
|
+
}
|
19
|
+
|
20
|
+
it "should successfully decrypt an encrypted file" do
|
21
|
+
String.from_java_bytes(decryptor.decrypt_stream(PGP.string_to_bais encrypted_text)).should == unencrypted_text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -4,19 +4,73 @@ describe PGP::Encryptor do
|
|
4
4
|
let(:private_key_path) { Fixtures_Path.join('private_key.asc').to_s }
|
5
5
|
let(:public_key_path) { Fixtures_Path.join('public_key.asc').to_s }
|
6
6
|
|
7
|
+
let(:encryptor) { PGP::Encryptor.new }
|
8
|
+
let(:string) { "FooBar" }
|
9
|
+
|
10
|
+
describe '#initialize' do
|
11
|
+
let(:encryptor) { PGP::Encryptor.new(File.read public_key_path) }
|
12
|
+
|
13
|
+
it "should accept public key(s) as an argument" do
|
14
|
+
encrypted_string = encryptor.encrypt(string, "some filename.txt")
|
15
|
+
|
16
|
+
PGP::RubyDecryptor.decrypt(encrypted_string, private_key_path).should == string
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
describe '#encrypt' do
|
8
|
-
|
9
|
-
|
21
|
+
context 'When the Public Key is from a file' do
|
22
|
+
before {
|
23
|
+
encryptor.add_keys_from_file(public_key_path)
|
24
|
+
}
|
25
|
+
|
26
|
+
it "it's encrypted string should be decryptable. durr" do
|
27
|
+
encrypted_string = encryptor.encrypt(string, "some filename.txt")
|
28
|
+
|
29
|
+
PGP::RubyDecryptor.decrypt(encrypted_string, private_key_path).should == string
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not require that a filename be specified" do
|
33
|
+
encrypted_string = encryptor.encrypt(string)
|
34
|
+
|
35
|
+
PGP::RubyDecryptor.decrypt(encrypted_string, private_key_path).should == string
|
36
|
+
end
|
37
|
+
end # context 'When the Public Key is from a file'
|
38
|
+
|
39
|
+
context 'When the Public Key has been read in to memory' do
|
40
|
+
before {
|
41
|
+
encryptor.add_keys(File.read public_key_path)
|
42
|
+
}
|
43
|
+
|
44
|
+
it "it's encrypted string should be decryptable. durr" do
|
45
|
+
encrypted_string = encryptor.encrypt(string, "some filename.txt")
|
46
|
+
|
47
|
+
PGP::RubyDecryptor.decrypt(encrypted_string, private_key_path).should == string
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not require that a filename be specified" do
|
51
|
+
encrypted_string = encryptor.encrypt(string)
|
52
|
+
|
53
|
+
PGP::RubyDecryptor.decrypt(encrypted_string, private_key_path).should == string
|
54
|
+
end
|
55
|
+
end # context 'When the Public Key has been read in to memory'
|
56
|
+
|
57
|
+
end # describe '#encrypt'
|
58
|
+
|
59
|
+
describe '#encrypt_file' do
|
60
|
+
let(:file_path) { Fixtures_Path.join('unencrypted_file.txt') }
|
61
|
+
let(:contents) { File.read(file_path) }
|
10
62
|
|
11
63
|
before {
|
12
|
-
encryptor.
|
64
|
+
encryptor.add_keys(File.read public_key_path)
|
13
65
|
}
|
14
66
|
|
15
|
-
|
16
|
-
encrypted_string = encryptor.encrypt(string.to_java_bytes, "some filename")
|
67
|
+
pending "should have an encryptStream method to avoid memory bloat"
|
17
68
|
|
18
|
-
|
69
|
+
it "should encrypt a file" do
|
70
|
+
encrypted_file = encryptor.encrypt_file(file_path)
|
71
|
+
|
72
|
+
PGP::RubyDecryptor.decrypt(encrypted_file, private_key_path).should == contents
|
19
73
|
end
|
20
|
-
end
|
74
|
+
end # describe '#encrypt_file'
|
21
75
|
|
22
76
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Top Secret Stuff
|
@@ -0,0 +1,19 @@
|
|
1
|
+
-----BEGIN PGP MESSAGE-----
|
2
|
+
Version: BCPG v1.47
|
3
|
+
|
4
|
+
hQEMA0hQjTEd00ExAQgAq2/daWwiAyNXrQVmJeWa7lM9oSFN1gae+yNVz7zysicw
|
5
|
+
B7KxUxOtDm4bmNfV72aQxzqOF1+vbn9NFv+beoat9/ZtqfSRSPeMow8AZSSii8Cp
|
6
|
+
I31xMfsbmzCKOQHqto3tNHU1bcyD8fF3STVo2bsbohUcAJ0wGQker+dQqqxBfElp
|
7
|
+
iLJQTQY+0DXwujV4w3+k+I5IeWPDuviqc7BVqKxq/pISbcre2OmS7wl63FCIimPW
|
8
|
+
2PHW+B9s9aEwTbaJNqr9Dc98xWmrmbQlnWi1U/RCHHpZpV3ME7HwH3bBHB5/HzLe
|
9
|
+
Zt4SHZU8TV2iIZTauEnlr24GJ7thbc6mP+KMaN2xNIUBDAMhK4YyQS5dIQEIAI6r
|
10
|
+
2UIYIyl8MY8uGZbm9oIp+HbQvL7Uu7CggHc2+L9fJovGGw1iAvywIGFxyuVQKe/m
|
11
|
+
QYcAgPIKwrSV6OAE4mZkV9yqBQkKiQMoYlzS4ZwBgle+6PiUeJBFoh5suTcxHn3I
|
12
|
+
wKkeSHZ/zZsfh5skC5jvp1d8K6aplL1NoRsXEXDkOSzAL//CVF6gnvRWmVe4Rt9u
|
13
|
+
lfwHiEa7k1HAkS9Gb3GBhLFSTY/ZxoiZMtXWT86P8KI5zwfFLOE2SbpvBGs9OCeD
|
14
|
+
DNDH3HA1jG7n9YpAc1pmqok4s/j5X4uJkJDRU0bQo2J3rcfS6tXRMSnWjqWAVTp5
|
15
|
+
24YnhPb/ee2+w20xP6zSUgHH1na+O4vmNgRHDGBjgWCzEcqJCW45OpcQ+rl/1VmT
|
16
|
+
nGSYc3FZA3+JPtBU98pAHrbPEeFBLOWoEc9mb0nS0f8OTky8ZJkzp2EQ1SsH+jV4
|
17
|
+
ZIk=
|
18
|
+
=15jR
|
19
|
+
-----END PGP MESSAGE-----
|
metadata
CHANGED
@@ -1,111 +1,134 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: jruby-pgp
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
|
9
|
-
autorequire:
|
7
|
+
authors:
|
8
|
+
- Scott Gonyea
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
12
|
+
date: 2012-11-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ! '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: !binary |-
|
21
|
+
MA==
|
22
|
+
none: false
|
23
|
+
requirement: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ! '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: !binary |-
|
28
|
+
MA==
|
29
|
+
none: false
|
30
|
+
prerelease: false
|
31
|
+
type: :development
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rspec
|
34
|
+
version_requirements: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: !binary |-
|
39
|
+
MA==
|
40
|
+
none: false
|
41
|
+
requirement: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: !binary |-
|
46
|
+
MA==
|
47
|
+
none: false
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rake-compiler
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: !binary |-
|
57
|
+
MA==
|
58
|
+
none: false
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: !binary |-
|
64
|
+
MA==
|
65
|
+
none: false
|
66
|
+
prerelease: false
|
67
|
+
type: :development
|
48
68
|
description: PGP for JRuby
|
49
|
-
email:
|
50
|
-
|
69
|
+
email:
|
70
|
+
- me@sgonyea.com
|
51
71
|
executables: []
|
52
|
-
|
53
72
|
extensions: []
|
54
|
-
|
55
73
|
extra_rdoc_files: []
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
files:
|
75
|
+
- .gitignore
|
76
|
+
- .rspec
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- ext/org/sgonyea/pgp/Decryptor.java
|
82
|
+
- ext/org/sgonyea/pgp/Encryptor.java
|
83
|
+
- jruby-pgp.gemspec
|
84
|
+
- lib/jruby-pgp.rb
|
85
|
+
- lib/pgp.rb
|
86
|
+
- lib/pgp/decryptor.rb
|
87
|
+
- lib/pgp/encryptor.rb
|
88
|
+
- lib/pgp/jars/bcpg-jdk15on-147.jar
|
89
|
+
- lib/pgp/jars/bcprov-jdk15on-147.jar
|
90
|
+
- lib/pgp/private_key.rb
|
91
|
+
- lib/pgp/ruby_decryptor.rb
|
92
|
+
- lib/pgp/version.rb
|
93
|
+
- spec/lib/pgp/decryptor_spec.rb
|
94
|
+
- spec/lib/pgp/encryptor_spec.rb
|
95
|
+
- spec/spec_helper.rb
|
96
|
+
- spec/support/fixtures/private_key.asc
|
97
|
+
- spec/support/fixtures/public_key.asc
|
98
|
+
- spec/support/fixtures/unencrypted_file.txt
|
99
|
+
- spec/support/fixtures/unencrypted_file.txt.asc
|
100
|
+
- lib/pgp/jruby-pgp.jar
|
80
101
|
homepage: https://github.com/sgonyea/jruby-pgp
|
81
102
|
licenses: []
|
82
|
-
|
83
|
-
post_install_message:
|
103
|
+
post_install_message:
|
84
104
|
rdoc_options: []
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: !binary |-
|
112
|
+
MA==
|
89
113
|
none: false
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: !binary |-
|
119
|
+
MA==
|
95
120
|
none: false
|
96
|
-
requirements:
|
97
|
-
- - ">="
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: "0"
|
100
121
|
requirements: []
|
101
|
-
|
102
|
-
rubyforge_project:
|
122
|
+
rubyforge_project:
|
103
123
|
rubygems_version: 1.8.24
|
104
|
-
signing_key:
|
124
|
+
signing_key:
|
105
125
|
specification_version: 3
|
106
126
|
summary: This is a Java+JRuby wrapper around the Bouncy Castle PGP APIs
|
107
|
-
test_files:
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
127
|
+
test_files:
|
128
|
+
- spec/lib/pgp/decryptor_spec.rb
|
129
|
+
- spec/lib/pgp/encryptor_spec.rb
|
130
|
+
- spec/spec_helper.rb
|
131
|
+
- spec/support/fixtures/private_key.asc
|
132
|
+
- spec/support/fixtures/public_key.asc
|
133
|
+
- spec/support/fixtures/unencrypted_file.txt
|
134
|
+
- spec/support/fixtures/unencrypted_file.txt.asc
|
@@ -1,49 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Much of this code was stolen from this Stack Overflow post:
|
3
|
-
* http://stackoverflow.com/questions/3939447/how-to-encrypt-a-string-stream-with-bouncycastle-pgp-without-starting-with-a-fil
|
4
|
-
*
|
5
|
-
* In addition to the java versions of this lump of code, that have been floating around on the internet:
|
6
|
-
* https://gist.github.com/1954648
|
7
|
-
*
|
8
|
-
* Thanks to everyone who has posted on the topic of Bouncy Castle's PGP Library.
|
9
|
-
*/
|
10
|
-
|
11
|
-
package org.sgonyea.pgp;
|
12
|
-
|
13
|
-
import java.io.ByteArrayInputStream;
|
14
|
-
import java.io.ByteArrayOutputStream;
|
15
|
-
import java.io.File;
|
16
|
-
import java.io.FileInputStream;
|
17
|
-
import java.io.FileOutputStream;
|
18
|
-
import java.io.IOException;
|
19
|
-
import java.io.InputStream;
|
20
|
-
import java.io.OutputStream;
|
21
|
-
import java.security.NoSuchProviderException;
|
22
|
-
import java.security.SecureRandom;
|
23
|
-
import java.security.Security;
|
24
|
-
import java.util.Date;
|
25
|
-
import java.util.Iterator;
|
26
|
-
|
27
|
-
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
28
|
-
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
29
|
-
import org.bouncycastle.openpgp.PGPCompressedData;
|
30
|
-
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
|
31
|
-
import org.bouncycastle.openpgp.PGPEncryptedData;
|
32
|
-
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
|
33
|
-
import org.bouncycastle.openpgp.PGPEncryptedDataList;
|
34
|
-
import org.bouncycastle.openpgp.PGPException;
|
35
|
-
import org.bouncycastle.openpgp.PGPLiteralData;
|
36
|
-
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
|
37
|
-
import org.bouncycastle.openpgp.PGPObjectFactory;
|
38
|
-
import org.bouncycastle.openpgp.PGPPrivateKey;
|
39
|
-
import org.bouncycastle.openpgp.PGPPublicKey;
|
40
|
-
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
|
41
|
-
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
42
|
-
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
43
|
-
import org.bouncycastle.openpgp.PGPSecretKey;
|
44
|
-
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
45
|
-
import org.bouncycastle.openpgp.PGPUtil;
|
46
|
-
|
47
|
-
public class PGP {
|
48
|
-
|
49
|
-
}
|