jruby-pgp 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
}
|