1
10package org.jstk.pem;
11
12import java.io.BufferedReader;
13import java.io.FileReader;
14import java.io.IOException;
15import java.io.InputStream;
16import java.io.FileInputStream;
17import java.io.BufferedInputStream;
18import java.io.ByteArrayInputStream;
19import java.io.ByteArrayOutputStream;
20
21public class PEMData {
22 private String preEB = null;
23 private String postEB = null;
24 private String text = null;
25 private byte[] raw = null;
26
27 private static final int BEGIN = 0;
28 private static final int GOT_PREEB = 1;
29 private static final int GOT_POSTEB = 2;
30
31 private static final String MARKER = "-----";
32
33 public PEMData(String text){
34 this.text = text;
35 }
36
37 public PEMData(BufferedReader reader) throws IOException, InvalidPEMFormatException {
38 String curLine;
39 int state = BEGIN;
40 StringBuffer sb = new StringBuffer();
41 while ((curLine = reader.readLine()) != null){
42 if (state == BEGIN){
43 if (curLine.startsWith(MARKER) && curLine.endsWith(MARKER)){
44 preEB = curLine;
45 state = GOT_PREEB;
46 } else {
47 throw new InvalidPEMFormatException("no PreEB");
48 }
49 } else if (state == GOT_PREEB){
50 if (curLine.startsWith(MARKER) && curLine.endsWith(MARKER)){
51 postEB = curLine;
52 state = GOT_POSTEB;
53 } else {
54 sb.append(curLine);
55 }
56 } else if (state == GOT_POSTEB){
57 throw new InvalidPEMFormatException("data after PostEB");
58 }
59 }
60 if (state != GOT_POSTEB){
61 throw new InvalidPEMFormatException("no PostEB");
62 }
63 text = sb.toString();
64 }
65
66 public PEMData(byte[] raw){
67 this(raw, "", "");
68 }
69
70 public PEMData(byte[] raw, String preEB, String postEB){
71 this.raw = raw;
72 this.preEB = preEB;
73 this.postEB = postEB;
74 }
75
76 public String getPreEB(){
77 return preEB;
78 }
79 public String getPostEB(){
80 return postEB;
81 }
82 public String getText(){
83 return text;
84 }
85 public byte[] decode() throws InvalidPEMFormatException {
86 if (text != null)
87 return decode(text);
88 return null;
89 }
90 public byte[] decode(String base64) throws InvalidPEMFormatException {
91 try {
92 int pad = 0;
93 for (int i = base64.length() - 1; (i > 0) && (base64.charAt(i) == '='); i--){
94 pad++;
95 }
96
97 int length = base64.length() / 4 * 3 - pad;
98 raw = new byte[length];
99
00 for (int i = 0, rawIndex = 0; i < base64.length(); i += 4, rawIndex += 3){
01 int block = (getValue(base64.charAt(i)) << 18)
02 + (getValue(base64.charAt(i + 1)) << 12)
03 + (getValue(base64.charAt(i + 2)) << 6)
04 + (getValue(base64.charAt(i + 3)));
05
06 for (int j = 2; j >= 0; j--) {
07 if (rawIndex + j < raw.length) {
08 raw[rawIndex + j] = (byte) (block & 0xff);
09 }
10
11 block >>= 8;
12 }
13 }
14
15 return raw;
16 } catch (IndexOutOfBoundsException ex) {
17 throw new InvalidPEMFormatException("illegal bit length");
18 }
19 }
20
21 public String encode(){
22 if (raw != null)
23 return encode(raw);
24 return null;
25 }
26 public String encode(byte[] raw){
27 StringBuffer sb = new StringBuffer();
28 int n24bits = raw.length/3;
29 int rem = raw.length - (n24bits*3);
30 int niters = n24bits + (rem > 0 ? 1 : 0);
31
32 for (int i = 0; i < niters; i++){
33 int block = 0;
34 for (int j = 0; j < 3; j++){
35 int val = (i*3 + j < raw.length ? raw[i*3 + j] : 0);
36 block |= (0x000000ff & val);
37 if (j < 2)
38 block <<= 8;
39 }
40
41 for (int j = 0; j < 4; j++){
42 int bb = (block >> ((3-j)*6)) & 0x0000003f;
43 char ch = getChar(bb);
44 if (i == n24bits){
45 if ((rem == 1 && j > 1) || (rem == 2 && j > 2))
46 ch = '=';
47 }
48 sb.append(ch);
49 }
50 if (((i + 1) & 0x0000000f) == 0)
51 sb.append("\n");
52 }
53 text = sb.toString();
54 return text;
55 }
56
57 private int getValue(char c){
58 if ((c >= 'A') && (c <= 'Z'))
59 return c - 'A';
60 else if ((c >= 'a') && (c <= 'z'))
61 return c - 'a' + 26;
62 else if ((c >= '0') && (c <= '9'))
63 return c - '0' + 52;
64 else if (c == '+')
65 return 62;
66 else if (c == '/')
67 return 63;
68 else if (c == '=')
69 return 0;
70
71 return -1;
72 }
73
74 private char getChar(int b6bit){
75 if (b6bit >= 0 && b6bit < 26)
76 return (char)('A' + b6bit);
77 else if (b6bit < 52)
78 return (char)('a' + (b6bit - 26));
79 else if (b6bit < 62)
80 return (char)('0' + (b6bit - 52));
81 else if (b6bit == 62)
82 return '+';
83 else if (b6bit == 63)
84 return '/';
85 else {
86 System.err.println("ERROR: Invalid Input to PEMData.getChar(): " + b6bit);
87 return '\0';
88 }
89 }
90
91 public String toString(){
92 return ("PRE_EB: " + preEB + "\nTEXT: " + text + "\nPOST-EB: " + postEB);
93 }
94
95 public static InputStream getDERInputStream(String file) throws IOException {
96 InputStream is = null;
97 try { BufferedReader reader = new BufferedReader(new FileReader(file));
99 PEMData x = new PEMData(reader);
00 is = new ByteArrayInputStream(x.decode());
01 } catch (InvalidPEMFormatException exc){ is = new FileInputStream(file);
03 }
04 return is;
05 }
06
07 private static void printusageAndExit(){
08 System.out.println("Usage:: java org.jstk.pem.PEMData (encode|decode) (-infile <file>|-text <text>)");
09 System.exit(0);
10 }
11 public static void main(String[] args) throws Exception {
12 PEMData pemData = null;
13 String text = null;
14 String infile = null;
15
16 if (args.length == 3){
17 if (args[1].equals("-infile")){
18 infile = args[2];
19 } else if (args[1].equals("-text")){
20 text = args[2];
21 } else {
22 printusageAndExit();
23 }
24
25 if (args[0].equals("decode")){
26 if (infile != null){
27 BufferedReader reader = new BufferedReader(new FileReader(infile));
28 pemData = new PEMData(reader);
29 } else {
30 pemData = new PEMData(text);
31 }
32 byte[] raw = pemData.decode();
33 System.out.println(new String(raw));
34 } else if (args[0].equals("encode")){
35 if (infile != null){
36 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(infile));
37 ByteArrayOutputStream baos = new ByteArrayOutputStream();
38 byte[] buf = new byte[1024];
39 int n;
40 while ((n = bis.read(buf, 0, buf.length)) > 0){
41 baos.write(buf, 0, n);
42 }
43 pemData = new PEMData(baos.toByteArray());
44 } else {
45 pemData = new PEMData(text.getBytes());
46 }
47 text = pemData.encode();
48 System.out.println(text);
49 } else {
50 printusageAndExit();
51 }
52 } else {
53 printusageAndExit();
54 }
55 }
56}