SSH.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. package de.tudarmstadt.informatik.hostage.protocol;
  2. import java.io.IOException;
  3. import java.math.BigInteger;
  4. import java.nio.ByteBuffer;
  5. import java.security.SecureRandom;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
  9. import de.tudarmstadt.informatik.hostage.ssh.crypto.KeyMaterial;
  10. import de.tudarmstadt.informatik.hostage.ssh.crypto.PEMDecoder;
  11. import de.tudarmstadt.informatik.hostage.ssh.crypto.cipher.CBCMode;
  12. import de.tudarmstadt.informatik.hostage.ssh.crypto.cipher.DESede;
  13. import de.tudarmstadt.informatik.hostage.ssh.crypto.dh.DhExchange;
  14. import de.tudarmstadt.informatik.hostage.ssh.crypto.digest.MAC;
  15. import de.tudarmstadt.informatik.hostage.ssh.signature.DSAPrivateKey;
  16. import de.tudarmstadt.informatik.hostage.ssh.signature.DSASHA1Verify;
  17. import de.tudarmstadt.informatik.hostage.ssh.signature.DSASignature;
  18. import de.tudarmstadt.informatik.hostage.ssh.util.TypesReader;
  19. import de.tudarmstadt.informatik.hostage.ssh.util.TypesWriter;
  20. import de.tudarmstadt.informatik.hostage.wrapper.Packet;
  21. /**
  22. * SSH protocol.
  23. * Implementation of RFC documents 4250, 4251, 4252, 4253, 4254.
  24. * It can handle the following requests: Server Protocol, Key Exchange Init, Diffie-Hellman Key Exchange Init, New Keys,
  25. * Service Request, Connection Request, Channel Open Request, Channel Request.
  26. * @author Wulf Pfeiffer
  27. */
  28. public class SSH implements Protocol {
  29. /**
  30. * Represents the states of the protocol.
  31. */
  32. private enum STATE {
  33. NONE, SERVER_VERSION, CLIENT_VERSION, KEX_INIT, NEW_KEYS, USERAUTH, CONNECTION, CHANNEL, TERMINAL_CMD, TERMINAL_ENTER, CLOSED
  34. }
  35. /**
  36. * Denotes in which state the protocol is right now.
  37. */
  38. private STATE state = STATE.NONE;
  39. private boolean useEncryption = false;
  40. @Override
  41. public int getDefaultPort() {
  42. return 22;
  43. }
  44. @Override
  45. public TALK_FIRST whoTalksFirst() {
  46. return TALK_FIRST.SERVER;
  47. }
  48. @Override
  49. public List<Packet> processMessage(Packet requestPacket) {
  50. List<Packet> responsePackets = new ArrayList<Packet>();
  51. byte[] request = null;
  52. if (requestPacket != null) {
  53. request = requestPacket.getMessage();
  54. if (useEncryption) {
  55. request = decryptBytes(request);
  56. }
  57. }
  58. switch (state) {
  59. case NONE:
  60. responsePackets.add(new Packet(serverVersion + serverType + "\r\n"));
  61. state = STATE.SERVER_VERSION;
  62. break;
  63. case SERVER_VERSION:
  64. extractType(request);
  65. extractPayload(request);
  66. responsePackets.add(kexInit());
  67. state = STATE.CLIENT_VERSION;
  68. break;
  69. case CLIENT_VERSION:
  70. extractPubKey(request);
  71. responsePackets.add(dhKexReply());
  72. state = STATE.KEX_INIT;
  73. break;
  74. case KEX_INIT:
  75. responsePackets.add(newKeys());
  76. useEncryption = true;
  77. state = STATE.NEW_KEYS;
  78. break;
  79. case NEW_KEYS:
  80. responsePackets.add(serviceReply(request));
  81. state = STATE.USERAUTH;
  82. break;
  83. case USERAUTH:
  84. responsePackets.add(connectionReply(request));
  85. state = STATE.CONNECTION;
  86. break;
  87. case CONNECTION:
  88. responsePackets.add(channelOpenReply(request));
  89. state = STATE.CHANNEL;
  90. break;
  91. case CHANNEL:
  92. responsePackets.add(channelSuccessReply(request));
  93. responsePackets.add(terminalPrefix());
  94. state = STATE.TERMINAL_CMD;
  95. break;
  96. case TERMINAL_CMD:
  97. responsePackets.add(terminalReply(request));
  98. break;
  99. case CLOSED:
  100. break;
  101. default:
  102. state = STATE.CLOSED;
  103. break;
  104. }
  105. return responsePackets;
  106. }
  107. @Override
  108. public boolean isClosed() {
  109. return (state == STATE.CLOSED);
  110. }
  111. @Override
  112. public boolean isSecure() {
  113. return false;
  114. }
  115. @Override
  116. public Class<byte[]> getType() {
  117. return byte[].class;
  118. }
  119. @Override
  120. public String toString() {
  121. return "SSH";
  122. }
  123. /**
  124. * Wraps the packets with packet length and padding.
  125. *
  126. * @param response
  127. * content that is wrapped.
  128. * @return wrapped packet.
  129. */
  130. private Packet wrapPacket(byte[] response) {
  131. int packetLength = 5 + response.length; // 4 byte packet length, 1 byte padding length, payload length
  132. int paddingLengthCBS = cipherBlockSize
  133. - (packetLength % cipherBlockSize);
  134. int paddingLength8 = 8 - (packetLength % 8);
  135. int paddingLength = paddingLengthCBS > paddingLength8 ? paddingLengthCBS
  136. : paddingLength8;
  137. if (paddingLength < 4)
  138. paddingLength += cipherBlockSize;
  139. packetLength = packetLength + paddingLength - 4; // add padding string length to packet length
  140. byte[] packetLen = ByteBuffer.allocate(4).putInt(packetLength).array();
  141. byte[] paddingLen = { (byte) paddingLength };
  142. byte[] paddingString = HelperUtils.randomBytes(paddingLength);
  143. byte[] wrappedResponse = HelperUtils.concat(packetLen, paddingLen, response,
  144. paddingString);
  145. if (useEncryption) {
  146. byte[] mac = createMac(wrappedResponse);
  147. byte[] responseEnc = encryptBytes(wrappedResponse);
  148. wrappedResponse = HelperUtils.concat(responseEnc, mac);
  149. }
  150. packetNumber++;
  151. return new Packet(wrappedResponse);
  152. }
  153. /**
  154. * Encrypts a request with triple DES.
  155. *
  156. * @param request
  157. * that is encrypted.
  158. * @return encrypted request.
  159. */
  160. private byte[] encryptBytes(byte[] bytes) {
  161. byte[] responseEncrypted = new byte[bytes.length];
  162. for (int i = 0; i < bytes.length; i += 8) {
  163. cbcEncryption.transformBlock(bytes, i, responseEncrypted, i);
  164. }
  165. return responseEncrypted;
  166. }
  167. /**
  168. * Decrypts a request with triple DES.
  169. *
  170. * @param request
  171. * that is decrypted.
  172. * @return decrypted request.
  173. */
  174. private byte[] decryptBytes(byte[] request) {
  175. byte[] decryptedRequest = new byte[request.length
  176. - ((request.length % 8 == 0) ? 0 : 20)];
  177. for (int i = 0; i < decryptedRequest.length; i += 8) { // -12 wegen MAC
  178. cbcDecryption.transformBlock(request, i, decryptedRequest, i);
  179. }
  180. return decryptedRequest;
  181. }
  182. /**
  183. * Creates the SHA1 Mac with the given bytes.
  184. *
  185. * @param bytes
  186. * that are used for the Mac.
  187. * @return Mac.
  188. */
  189. private byte[] createMac(byte[] bytes) {
  190. byte[] mac = new byte[20];
  191. macEncryption.initMac(packetNumber);
  192. macEncryption.update(bytes, 0, bytes.length);
  193. macEncryption.getMac(mac, 0);
  194. return mac;
  195. }
  196. /**
  197. * Builds the Kex Init packet that contains all the allowed algorithms by
  198. * the server.
  199. *
  200. * @return Kex Init packet.
  201. */
  202. private Packet kexInit() {
  203. TypesWriter tw = new TypesWriter();
  204. tw.writeByte(0x14);
  205. tw.writeBytes(HelperUtils.randomBytes(16)); // cookie
  206. tw.writeString(KEX_ALG);
  207. tw.writeString(SERVER_ALG);
  208. tw.writeString(ENCRYPT_ALG_C);
  209. tw.writeString(ENCRYPT_ALG_S);
  210. tw.writeString(MAC_ALG_C);
  211. tw.writeString(MAC_ALG_S);
  212. tw.writeString(COMP_ALG_C);
  213. tw.writeString(COMP_ALG_S);
  214. tw.writeBytes(new byte[] { 0x00, 0x00, 0x00, 0x00 }); // language client to server
  215. tw.writeBytes(new byte[] { 0x00, 0x00, 0x00, 0x00 }); // language server to client
  216. tw.writeByte(0x00); // no guess from server
  217. tw.writeBytes(new byte[] { 0x00, 0x00, 0x00, 0x00 }); // reserved
  218. byte[] response = tw.getBytes();
  219. I_S = response;
  220. return wrapPacket(response);
  221. }
  222. /**
  223. * Builds the Diffie-Hellman Kex Reply, containing the host key,f and the
  224. * signature.
  225. *
  226. * @return Diffie-Hellman Kex Reply packet.
  227. */
  228. private Packet dhKexReply() {
  229. byte[] response = null;
  230. try {
  231. DhExchange dhx = new DhExchange();
  232. dhx.serverInit(1, random);
  233. dhx.setE(new BigInteger(e));
  234. f = dhx.getF();
  235. DSAPrivateKey dsa = (DSAPrivateKey) PEMDecoder
  236. .decode(dsaPem, null);
  237. K_S = DSASHA1Verify.encodeSSHDSAPublicKey(dsa.getPublicKey());
  238. h = dhx.calculateH(V_C, V_S, I_C, I_S, K_S);
  239. k = dhx.getK();
  240. DSASignature ds = DSASHA1Verify.generateSignature(h, dsa, random);
  241. signature = DSASHA1Verify.encodeSSHDSASignature(ds);
  242. TypesWriter tw = new TypesWriter();
  243. tw.writeByte(31);
  244. tw.writeString(K_S, 0, K_S.length);
  245. tw.writeMPInt(f);
  246. tw.writeString(signature, 0, signature.length);
  247. response = tw.getBytes();
  248. // init for decryption and encryption
  249. KeyMaterial km = KeyMaterial.create("SHA1", h, k, h, 24, 8, 20, 24,
  250. 8, 20); // alg, h, k, keylength, blocklength, maclength, keylength, blocklength, maclength
  251. desEncryption = new DESede();
  252. desDecryption = new DESede();
  253. desEncryption.init(true, km.enc_key_server_to_client);
  254. desDecryption.init(false, km.enc_key_client_to_server);
  255. cbcEncryption = new CBCMode(desEncryption, km.initial_iv_server_to_client, true);
  256. cbcDecryption = new CBCMode(desDecryption, km.initial_iv_client_to_server, false);
  257. macEncryption = new MAC("hmac-sha1", km.integrity_key_server_to_client);
  258. } catch (Exception e) {
  259. e.printStackTrace();
  260. }
  261. return wrapPacket(response);
  262. }
  263. /**
  264. * New Keys response.
  265. *
  266. * @return New Keys response.
  267. */
  268. private Packet newKeys() {
  269. byte[] msgCode = { 0x15 };
  270. return wrapPacket(msgCode);
  271. }
  272. /**
  273. * Service ssh-userauth reply.
  274. *
  275. * @param request
  276. * from the client.
  277. * @return Service reply.
  278. */
  279. private Packet serviceReply(byte[] request) {
  280. byte[] message;
  281. if (request[5] == 0x15) { // if newkeys request is included in the same packet
  282. message = new byte[request.length - 16]; // remove it
  283. System.arraycopy(request, 16, message, 0, request.length - 16);
  284. } else {
  285. message = request;
  286. }
  287. if (message[5] != 0x05
  288. && !(HelperUtils.byteToStr(message).contains("ssh-userauth"))) {
  289. return disconnectReply(7); // disconnect because its not servicerequest ssh-userauth
  290. }
  291. TypesWriter tw = new TypesWriter();
  292. tw.writeByte(0x06);
  293. tw.writeString("ssh-userauth");
  294. return wrapPacket(tw.getBytes());
  295. }
  296. /**
  297. * Userauth ssh-connection reply.
  298. *
  299. * @param request
  300. * from the client.
  301. * @return ssh-connection reply.
  302. */
  303. private Packet connectionReply(byte[] request) {
  304. if (request[5] != 0x32
  305. && !(HelperUtils.byteToStr(request).contains("ssh-connection"))) {
  306. return disconnectReply(14);// disconnect because its not servicerequest ssh-connect
  307. }
  308. try {
  309. TypesReader tr = new TypesReader(request, 6);
  310. userName = tr.readString();
  311. terminalPrefix = "[" + userName + "@" + serverName + "]$";
  312. } catch (IOException e) {
  313. e.printStackTrace();
  314. }
  315. byte[] msgcode = { 0x34 };
  316. return wrapPacket(msgcode);
  317. }
  318. /**
  319. * Channel Open Reply.
  320. *
  321. * @param request
  322. * from client.
  323. * @return Channel Open Reply.
  324. */
  325. private Packet channelOpenReply(byte[] request) {
  326. if (!(HelperUtils.byteToStr(request).contains("session"))) {
  327. return disconnectReply(2); // if contains "session" ok else disc
  328. }
  329. TypesReader tr = new TypesReader(request, 6);
  330. TypesWriter tw = new TypesWriter();
  331. try {
  332. tr.readString();
  333. recipientChannel = tr.readUINT32();
  334. int senderChannel = recipientChannel;
  335. int initialWindowSize = tr.readUINT32();
  336. int maximumPacketSize = tr.readUINT32();
  337. tw.writeByte(0x5b); // msgcode
  338. tw.writeUINT32(recipientChannel);
  339. tw.writeUINT32(senderChannel);
  340. tw.writeUINT32(initialWindowSize);
  341. tw.writeUINT32(maximumPacketSize);
  342. } catch (IOException e) {
  343. e.printStackTrace();
  344. }
  345. return wrapPacket(tw.getBytes());
  346. }
  347. /**
  348. * Channel Success Reply.
  349. *
  350. * @param request
  351. * from client.
  352. * @return Channel Success Reply.
  353. */
  354. private Packet channelSuccessReply(byte[] request) {
  355. if (!(HelperUtils.byteToStr(request)).contains("pty-req")) {
  356. return disconnectReply(2);
  357. }
  358. TypesWriter tw = new TypesWriter();
  359. tw.writeByte(0x63); // msgcode
  360. tw.writeUINT32(recipientChannel);
  361. return wrapPacket(tw.getBytes());
  362. }
  363. /**
  364. * Returns the terminal prefix for the client.
  365. *
  366. * @return terminal prefix.
  367. */
  368. private Packet terminalPrefix() {
  369. TypesWriter tw = new TypesWriter();
  370. tw.writeByte(0x5e);
  371. tw.writeUINT32(recipientChannel);
  372. tw.writeString(terminalPrefix);
  373. return wrapPacket(tw.getBytes());
  374. }
  375. /**
  376. * Computes the reply for the client input.
  377. *
  378. * @param request
  379. * client input.
  380. * @return input reply.
  381. */
  382. private Packet terminalReply(byte[] request) {
  383. TypesReader tr = new TypesReader(request, 6);
  384. String messsage = "";
  385. System.out.println(HelperUtils.bytesToHexString(request));
  386. try {
  387. tr.readUINT32();
  388. messsage = tr.readString();
  389. System.out.println(messsage);
  390. if (messsage.contains("\r")) {
  391. System.out.println("hi");
  392. if (command.toString().contains("exit")) {
  393. state = STATE.CLOSED; // ugly style
  394. return disconnectReply(2);
  395. }
  396. messsage = "\r\nbash: " + command + " :command not found\r\n"
  397. + terminalPrefix;
  398. command = new StringBuffer();
  399. } else if (messsage.contains(new String(new char[] { '\u007F' }))
  400. && command.length() > 0) {
  401. command = command.delete(command.length() - 1, command.length());
  402. } else {
  403. command.append(messsage);
  404. }
  405. } catch (IOException e) {
  406. e.printStackTrace();
  407. }
  408. TypesWriter tw = new TypesWriter();
  409. tw.writeByte(0x5e); // msgcode
  410. tw.writeUINT32(recipientChannel);
  411. tw.writeString(messsage);
  412. return wrapPacket(tw.getBytes());
  413. }
  414. /**
  415. * Disconnect Reply using the given number as reason code.
  416. *
  417. * @param reasonCode
  418. * for disconnect reply. Must be between 1 and 15, default is 2.
  419. * @return Disconnect Reply.
  420. */
  421. private Packet disconnectReply(int reasonCode) {
  422. TypesWriter tw = new TypesWriter();
  423. tw.writeByte(0x01);
  424. switch (reasonCode) {
  425. case 1:
  426. tw.writeUINT32(1);
  427. tw.writeString("SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT");
  428. break;
  429. case 7:
  430. tw.writeUINT32(7);
  431. tw.writeString("SSH_DISCONNECT_SERVICE_NOT_AVAILABLE");
  432. break;
  433. case 14:
  434. tw.writeUINT32(14);
  435. tw.writeString("SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE");
  436. break;
  437. default:
  438. tw.writeUINT32(2);
  439. tw.writeString("SSH_DISCONNECT_PROTOCOL_ERROR");
  440. break;
  441. }
  442. return wrapPacket(tw.getBytes());
  443. }
  444. /**
  445. * Extracts the type of the client
  446. *
  447. * @param request
  448. * containing the clients type
  449. */
  450. private void extractType(byte[] request) {
  451. int length = 0;
  452. for (int i = 0; i < request.length; i++, length++) {
  453. if (request[i] == 0x0d)
  454. break; // find the end of the type: '\r'
  455. }
  456. V_C = new byte[length];
  457. System.arraycopy(request, 0, V_C, 0, length);
  458. }
  459. /**
  460. * Extracts the payload of a packet and writes it in I_C.
  461. *
  462. * @param request
  463. * packet of which the payload is extracted.
  464. */
  465. private void extractPayload(byte[] request) {
  466. int position = 0;
  467. if (request[5] != 0x14) {
  468. position = 1;
  469. for (int i = 0; i < request.length; i++, position++) {
  470. if (request[i] == 0xa)
  471. break;
  472. }
  473. }
  474. int packetLength = byteToInt(new byte[] { request[position], request[1 + position], request[2 + position], request[3 + position] });
  475. int paddingLength = byteToInt(new byte[] { request[4 + position] });
  476. byte[] payload = new byte[packetLength - paddingLength - 1];
  477. for (int i = 5; i < packetLength - paddingLength - 1; i++) {
  478. payload[i - 5] = request[i + position];
  479. }
  480. I_C = payload;
  481. }
  482. /**
  483. * Extracts the public key from the DH Kex Request
  484. *
  485. * @param request
  486. * containing the clients public key
  487. */
  488. private void extractPubKey(byte[] request) {
  489. e = new byte[byteToInt(new byte[] { request[6], request[7], request[8],
  490. request[9] })];
  491. for (int i = 0; i < e.length; i++) {
  492. e[i] = request[i + 10];
  493. }
  494. }
  495. /**
  496. * Converts a byte[] to int
  497. *
  498. * @param bytes
  499. * that are converted
  500. * @return converted byte[] as int
  501. */
  502. private static int byteToInt(byte[] bytes) {
  503. int convertedInteger = 0;
  504. for (int i = 0; i < bytes.length; i++) {
  505. convertedInteger <<= 8;
  506. convertedInteger |= bytes[i] & 0xFF;
  507. }
  508. return convertedInteger;
  509. }
  510. // version stuff
  511. private static String[][][] possibleSshTypes = {
  512. { { "3." }, { "4", "5", "6", "7", "8", "9" } },
  513. { { "4." }, { "0", "1", "2", "3", "4", "5", "6", "7", "9" } },
  514. { { "5." }, { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" } },
  515. { { "6." }, { "0", "1", "2", "3", "4" } } };
  516. private static String initSshType() {
  517. SecureRandom rnd = new SecureRandom();
  518. int majorVersion = rnd.nextInt(possibleSshTypes.length);
  519. return "OpenSSH_"
  520. + possibleSshTypes[majorVersion][0][0]
  521. + possibleSshTypes[majorVersion][1][rnd
  522. .nextInt(possibleSshTypes[majorVersion][1].length)];
  523. }
  524. // server infos
  525. private static String serverVersion = "SSH-2.0-";
  526. private static String serverType = initSshType();
  527. private static String serverName = HelperUtils.getRandomString(16, false);
  528. private int packetNumber = 0;
  529. private int recipientChannel;
  530. private String userName;
  531. private String terminalPrefix;
  532. private StringBuffer command = new StringBuffer();
  533. private SecureRandom random = new SecureRandom();
  534. // SSH Parameters for Kex etc.
  535. private byte[] V_S = (serverVersion + serverType).getBytes();
  536. private byte[] V_C;
  537. private byte[] I_S;
  538. private byte[] I_C;
  539. private byte[] e;
  540. private BigInteger f;
  541. private byte[] h;
  542. private BigInteger k;
  543. private byte[] K_S;
  544. private byte[] signature;
  545. // allowed algorithms for kexinit
  546. private static final String KEX_ALG = "diffie-hellman-group1-sha1";
  547. private static final String SERVER_ALG = "ssh-dss";
  548. private static final String ENCRYPT_ALG_C = "3des-cbc";
  549. private static final String ENCRYPT_ALG_S = "3des-cbc";
  550. private static final String MAC_ALG_C = "hmac-sha1";
  551. private static final String MAC_ALG_S = "hmac-sha1";
  552. private static final String COMP_ALG_C = "none";
  553. private static final String COMP_ALG_S = "none";
  554. private int cipherBlockSize = 16;
  555. // for en- and decryption
  556. private DESede desEncryption;
  557. private DESede desDecryption;
  558. private CBCMode cbcEncryption;
  559. private CBCMode cbcDecryption;
  560. private MAC macEncryption;
  561. // private MAC macDec;
  562. // dsa private key
  563. private final char[] dsaPem = ("-----BEGIN DSA PRIVATE KEY-----\n"
  564. + "MIIBugIBAAKBgQCDZ9R2vfCPwjv5vKF1igIv9drrZ7G0dhMkGT9AZTjgI34Qm4w0\n"
  565. + "0iWeCqO7SmqiaMIjbRIm91MeDed4ObAq4sAkqRE/2P4mTbzFx5KhEczRRiDoqQBX\n"
  566. + "xYa0yWKJpeZ94SGM6DEPuBTxKo0T4uMjbq2FzHL2FXT1/WoNCmRU6gFSiwIVAMK4\n"
  567. + "Epz3JiwDUbkSpLOjIqtEhJmVAoGAL6zlXRI4Q8iwvSDh0vDf1j9a5Aaaq+93LTjK\n"
  568. + "SwL4nvUWBl2Aa0vqu05ZS5rOD1I+/naLMg0fNgFJRhA03sl+12MI3a2HXJWXRSdj\n"
  569. + "m1Vq9cUXqiYrX6+iGfEaA/y9UO4ZPF6if6eLypXB8VuqjtjDCiMMsM6+qQki7L71\n"
  570. + "yN4M75ICgYAcFXUhN2zRug3JvwmGxW8gMgHquSiBnbx1582KGh2B/ukE/kOrbKYD\n"
  571. + "HUkBzolcm4x1Odq5apowlriFxY6zMQP615plIK4x9NaU6dvc/HoTkjzT5EYSMN39\n"
  572. + "eAGufJ0jrtIpKL4lP8o8yrAHfmbR7bjecWc0viTH0+OWlyVsex/bZAIUEKn310Li\n"
  573. + "v62Zs4hlDvhwvx8MQ+A=\n" + "-----END DSA PRIVATE KEY-----")
  574. .toCharArray();
  575. }