Mercurial > 510Connectbot
comparison src/com/five_ten_sg/connectbot/util/EntropyView.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0ce5cc452d02 |
---|---|
1 /* | |
2 * ConnectBot: simple, powerful, open-source SSH client for Android | |
3 * Copyright 2007 Kenny Root, Jeffrey Sharkey | |
4 * | |
5 * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 * you may not use this file except in compliance with the License. | |
7 * You may obtain a copy of the License at | |
8 * | |
9 * http://www.apache.org/licenses/LICENSE-2.0 | |
10 * | |
11 * Unless required by applicable law or agreed to in writing, software | |
12 * distributed under the License is distributed on an "AS IS" BASIS, | |
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 * See the License for the specific language governing permissions and | |
15 * limitations under the License. | |
16 */ | |
17 | |
18 package com.five_ten_sg.connectbot.util; | |
19 | |
20 import java.util.Vector; | |
21 | |
22 import com.five_ten_sg.connectbot.R; | |
23 import android.content.Context; | |
24 import android.graphics.Canvas; | |
25 import android.graphics.Color; | |
26 import android.graphics.Paint; | |
27 import android.graphics.Paint.FontMetrics; | |
28 import android.graphics.Typeface; | |
29 import android.util.AttributeSet; | |
30 import android.view.MotionEvent; | |
31 import android.view.View; | |
32 | |
33 public class EntropyView extends View { | |
34 private static final int SHA1_MAX_BYTES = 20; | |
35 private static final int MILLIS_BETWEEN_INPUTS = 50; | |
36 | |
37 private Paint mPaint; | |
38 private FontMetrics mFontMetrics; | |
39 private boolean mFlipFlop; | |
40 private long mLastTime; | |
41 private Vector<OnEntropyGatheredListener> listeners; | |
42 | |
43 private byte[] mEntropy; | |
44 private int mEntropyByteIndex; | |
45 private int mEntropyBitIndex; | |
46 | |
47 private int splitText = 0; | |
48 | |
49 private float lastX = 0.0f, lastY = 0.0f; | |
50 | |
51 public EntropyView(Context context) { | |
52 super(context); | |
53 setUpEntropy(); | |
54 } | |
55 | |
56 public EntropyView(Context context, AttributeSet attrs) { | |
57 super(context, attrs); | |
58 setUpEntropy(); | |
59 } | |
60 | |
61 private void setUpEntropy() { | |
62 mPaint = new Paint(); | |
63 mPaint.setAntiAlias(true); | |
64 mPaint.setTypeface(Typeface.DEFAULT); | |
65 mPaint.setTextAlign(Paint.Align.CENTER); | |
66 mPaint.setTextSize(16); | |
67 mPaint.setColor(Color.WHITE); | |
68 mFontMetrics = mPaint.getFontMetrics(); | |
69 mEntropy = new byte[SHA1_MAX_BYTES]; | |
70 mEntropyByteIndex = 0; | |
71 mEntropyBitIndex = 0; | |
72 listeners = new Vector<OnEntropyGatheredListener>(); | |
73 } | |
74 | |
75 public void addOnEntropyGatheredListener(OnEntropyGatheredListener listener) { | |
76 listeners.add(listener); | |
77 } | |
78 | |
79 public void removeOnEntropyGatheredListener(OnEntropyGatheredListener listener) { | |
80 listeners.remove(listener); | |
81 } | |
82 | |
83 @Override | |
84 public void onDraw(Canvas c) { | |
85 String prompt = String.format(getResources().getString(R.string.pubkey_touch_prompt), | |
86 (int)(100.0 * (mEntropyByteIndex / 20.0)) + (int)(5.0 * (mEntropyBitIndex / 8.0))); | |
87 | |
88 if (splitText > 0 || | |
89 mPaint.measureText(prompt) > (getWidth() * 0.8)) { | |
90 if (splitText == 0) | |
91 splitText = prompt.indexOf(" ", prompt.length() / 2); | |
92 | |
93 c.drawText(prompt.substring(0, splitText), | |
94 getWidth() / 2.0f, | |
95 getHeight() / 2.0f + (mPaint.ascent() + mPaint.descent()), | |
96 mPaint); | |
97 c.drawText(prompt.substring(splitText), | |
98 getWidth() / 2.0f, | |
99 getHeight() / 2.0f - (mPaint.ascent() + mPaint.descent()), | |
100 mPaint); | |
101 } | |
102 else { | |
103 c.drawText(prompt, | |
104 getWidth() / 2.0f, | |
105 getHeight() / 2.0f - (mFontMetrics.ascent + mFontMetrics.descent) / 2, | |
106 mPaint); | |
107 } | |
108 } | |
109 | |
110 @Override | |
111 public boolean onTouchEvent(MotionEvent event) { | |
112 if (mEntropyByteIndex >= SHA1_MAX_BYTES | |
113 || lastX == event.getX() | |
114 || lastY == event.getY()) | |
115 return true; | |
116 | |
117 // Only get entropy every 200 milliseconds to ensure the user has moved around. | |
118 long now = System.currentTimeMillis(); | |
119 | |
120 if ((now - mLastTime) < MILLIS_BETWEEN_INPUTS) | |
121 return true; | |
122 else | |
123 mLastTime = now; | |
124 | |
125 byte input; | |
126 lastX = event.getX(); | |
127 lastY = event.getY(); | |
128 | |
129 // Get the lowest 4 bits of each X, Y input and concat to the entropy-gathering | |
130 // string. | |
131 if (mFlipFlop) | |
132 input = (byte)((((int)lastX & 0x0F) << 4) | ((int)lastY & 0x0F)); | |
133 else | |
134 input = (byte)((((int)lastY & 0x0F) << 4) | ((int)lastX & 0x0F)); | |
135 | |
136 mFlipFlop = !mFlipFlop; | |
137 | |
138 for (int i = 0; i < 4 && mEntropyByteIndex < SHA1_MAX_BYTES; i++) { | |
139 if ((input & 0x3) == 0x1) { | |
140 mEntropy[mEntropyByteIndex] <<= 1; | |
141 mEntropy[mEntropyByteIndex] |= 1; | |
142 mEntropyBitIndex++; | |
143 input >>= 2; | |
144 } | |
145 else if ((input & 0x3) == 0x2) { | |
146 mEntropy[mEntropyByteIndex] <<= 1; | |
147 mEntropyBitIndex++; | |
148 input >>= 2; | |
149 } | |
150 | |
151 if (mEntropyBitIndex >= 8) { | |
152 mEntropyBitIndex = 0; | |
153 mEntropyByteIndex++; | |
154 } | |
155 } | |
156 | |
157 // SHA1PRNG only keeps 160 bits of entropy. | |
158 if (mEntropyByteIndex >= SHA1_MAX_BYTES) { | |
159 for (OnEntropyGatheredListener listener : listeners) { | |
160 listener.onEntropyGathered(mEntropy); | |
161 } | |
162 } | |
163 | |
164 invalidate(); | |
165 return true; | |
166 } | |
167 } |