RandomSeedViewController.m 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2015-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "RandomSeedViewController.h"
  21. #import "BundleUtil.h"
  22. #import "MotionEntropyCollector.h"
  23. #import "NaClCrypto.h"
  24. #import <CommonCrypto/CommonDigest.h>
  25. #import "NSString+Hex.h"
  26. #import "UIDefines.h"
  27. #import "RectUtil.h"
  28. #import "LicenseStore.h"
  29. #import "ThreemaFramework/ThreemaFramework-swift.h"
  30. #define NUM_POSITIONS_REQUIRED 200
  31. #define NUM_LINES 16
  32. #define NUM_BYTES 16
  33. #define CHARACTER_SPACING 8.0
  34. #define LINE_SPACING 6.0
  35. @interface RandomSeedViewController () <MoveFingerDelegate>
  36. @property MotionEntropyCollector *motionEntropyCollector;
  37. @property BOOL doneCollecting;
  38. @property BOOL startedCollectiong;
  39. @property NSString *randomString;
  40. @property NSMutableAttributedString *attributedString;
  41. @property NSMutableArray *labelMatrix;
  42. @property CGFloat accessabilityLastProgress;
  43. @end
  44. @implementation RandomSeedViewController
  45. - (void)viewDidLoad {
  46. [super viewDidLoad];
  47. [self setup];
  48. }
  49. - (void)adaptToSmallScreen {
  50. [super adaptToSmallScreen];
  51. CGFloat yOffset = -20.0;
  52. _titleLabel.frame = [RectUtil offsetRect:_titleLabel.frame byX:0.0 byY:yOffset];
  53. yOffset -= 24.0;
  54. _actionLabel.frame = [RectUtil offsetRect:_actionLabel.frame byX:0.0 byY:yOffset];
  55. _progressView.frame = [RectUtil offsetRect:_progressView.frame byX:0.0 byY:yOffset];
  56. _randomDataView.frame = [RectUtil offsetRect:_randomDataView.frame byX:0.0 byY:yOffset];
  57. _fingerView.frame = [RectUtil offsetRect:_fingerView.frame byX:0.0 byY:yOffset];
  58. yOffset = 48.0;
  59. self.moreView.frame = [RectUtil offsetRect:self.moreView.frame byX:0.0 byY:yOffset];
  60. }
  61. - (void)setup {
  62. _randomDataBackground.layer.cornerRadius = 5.0;
  63. _progressView.tintColor = [Colors mainThemeDark];
  64. if ([LicenseStore requiresLicenseKey]) {
  65. _titleLabel.text = [BundleUtil localizedStringForKey:@"welcome_work"];
  66. } else {
  67. _titleLabel.text = [BundleUtil localizedStringForKey:@"welcome"];
  68. }
  69. _actionLabel.text = [BundleUtil localizedStringForKey:@"move_your_finger"];
  70. self.moreView.mainView = self.mainContentView;
  71. self.moreView.moreButtonTitle = [BundleUtil localizedStringForKey:@"more_information"];
  72. self.moreView.moreMessageText = [BundleUtil localizedStringForKey:@"more_information_random_seed"];
  73. _motionEntropyCollector = [[MotionEntropyCollector alloc] init];
  74. _randomDataView.delegate = self;
  75. _randomDataView.isAccessibilityElement = YES;
  76. [_randomDataView setAccessibilityHint:[BundleUtil localizedStringForKey:@"move_your_finger"]];
  77. _randomDataView.accessibilityIdentifier = @"randomDataView";
  78. [self setupRandomMatrix];
  79. [self progressUpdate];
  80. [_motionEntropyCollector start];
  81. self.view.backgroundColor = [UIColor clearColor];
  82. _accessabilityLastProgress = 0.0;
  83. _fingerView.image = [StyleKit finger];
  84. }
  85. - (void)setupRandomMatrix {
  86. CGFloat size = _randomDataView.frame.size.width / NUM_BYTES;
  87. _labelMatrix = [NSMutableArray arrayWithCapacity:NUM_LINES*NUM_BYTES];
  88. NSData *random = [[NaClCrypto sharedCrypto] randomBytes:(NUM_LINES*NUM_BYTES)];
  89. NSString *randomString = [NSString stringWithHexData:random];
  90. randomString = [randomString uppercaseString];
  91. for (int n = 0; n < NUM_LINES; n++) {
  92. for (int i = 0; i < NUM_BYTES; i++) {
  93. CGRect rect = CGRectMake(i*size, n*size, size, size);
  94. UILabel *label = [self charLabelAt:rect];
  95. label.text = [randomString substringWithRange:NSMakeRange((i+1)*(n+1), 1)];
  96. label.isAccessibilityElement = NO;
  97. [_randomDataView addSubview:label];
  98. [_labelMatrix addObject:label];
  99. }
  100. }
  101. }
  102. - (UILabel *)charLabelAt:(CGRect)rect {
  103. UILabel *label = [[UILabel alloc] initWithFrame:rect];
  104. label.font = [UIFont systemFontOfSize:12];
  105. label.textColor = THREEMA_COLOR_LIGHT_GREY;
  106. label.textAlignment = NSTextAlignmentCenter;
  107. label.lineBreakMode = NSLineBreakByClipping;
  108. label.backgroundColor = [UIColor clearColor];
  109. return label;
  110. }
  111. - (void)dealloc {
  112. [_motionEntropyCollector stop];
  113. }
  114. - (void)didMoveFingerInView:(MoveFingerView *)view {
  115. if (_startedCollectiong == NO) {
  116. _startedCollectiong = YES;
  117. [UIView animateWithDuration:0.3 animations:^{
  118. _fingerView.alpha = 0.0;
  119. } completion:^(BOOL finished) {
  120. _fingerView.hidden = YES;
  121. }];
  122. }
  123. [self progressUpdate];
  124. if (_randomDataView.numberOfPositionsRecorded >= NUM_POSITIONS_REQUIRED && !_doneCollecting) {
  125. /* done! */
  126. _doneCollecting = YES;
  127. NSData *seed = [self getSeed];
  128. if ([_delegate respondsToSelector: @selector(generatedRandomSeed:)]) {
  129. [_delegate generatedRandomSeed:seed];
  130. }
  131. }
  132. }
  133. - (void)progressUpdate {
  134. CGFloat progress = (float)_randomDataView.numberOfPositionsRecorded / NUM_POSITIONS_REQUIRED;
  135. _progressView.progress = progress;
  136. if (progress >= 1.0) {
  137. for (UILabel *label in _labelMatrix) {
  138. label.textColor = [Colors mainThemeDark];
  139. }
  140. dispatch_async(dispatch_get_main_queue(), ^{
  141. UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [BundleUtil localizedStringForKey:@"done"]);
  142. });
  143. } else if (progress > 0) {
  144. int posIncrement = 1.0/progress + arc4random() % 5;
  145. for (int i=0; i < _labelMatrix.count; i += posIncrement) {
  146. // some randomness if the color should change
  147. int random = arc4random();
  148. if (random % 10 > 8) {
  149. UILabel *label = _labelMatrix[i];
  150. label.textColor = [Colors mainThemeDark];
  151. }
  152. }
  153. if (progress - _accessabilityLastProgress >= 0.1) {
  154. dispatch_async(dispatch_get_main_queue(), ^{
  155. UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, _progressView.accessibilityValue);
  156. });
  157. _accessabilityLastProgress = progress;
  158. }
  159. }
  160. }
  161. - (NSData *)getSeed {
  162. NSData *motionSeed = [_motionEntropyCollector stop];
  163. NSData *fingerSeed = _randomDataView.digest;
  164. /* mix the two seeds */
  165. CC_SHA256_CTX ctx;
  166. CC_SHA256_Init(&ctx);
  167. if (motionSeed.length > 0)
  168. CC_SHA256_Update(&ctx, motionSeed.bytes, (CC_LONG)motionSeed.length);
  169. if (fingerSeed.length > 0)
  170. CC_SHA256_Update(&ctx, fingerSeed.bytes, (CC_LONG)fingerSeed.length);
  171. unsigned char digest[CC_SHA256_DIGEST_LENGTH];
  172. CC_SHA256_Final(digest, &ctx);
  173. NSData *seed = [NSData dataWithBytes:digest length:sizeof(digest)];
  174. return seed;
  175. }
  176. @end