Permalink
Browse files

Open sourcing to the community

By popular request, the code is now open source. Looking forward to
your feedback ahead of declaring version 1.0 fit for production…
  • Loading branch information...
ylechelle committed Mar 18, 2014
1 parent 4083300 commit f8c726c1ac2bfa67335b5de8d3e9f8ddd0f69d0a
Showing with 263 additions and 46 deletions.
  1. +16 −2 OpenIDFA.h
  2. +237 −0 OpenIDFA.m
  3. +0 −33 OpenIDFA.podspec
  4. +10 −11 README.md
  5. BIN libOpenIDFA.a
View
@@ -1,9 +1,23 @@
//
// OpenIDFA.h
//
// Created by Yann Lechelle on 07 Feb 2014.
// NON PRODUCTION RELEASE VERSION 0.9
//
// Authored by Yann Lechelle on 07 Feb 2014.
// Open sourced to early adopters for private peer-review on 12 Feb 2014.
// Updated for stability on 19 Feb 2014.
// Open sourced to the wider community on 18 March 2014.
// Copyright (c) 2014 APPSFIRE.
// This Library is released under the Creative Commons licence with "Attribution No Derivatives" (CC BY-ND)
//
// Homepage: http://OpenIDFA.org
// Twitter: @openIDFA
//
// This piece of code is released under the Creative Commons licence with "Attribution + No Derivatives" (CC BY-ND) http://creativecommons.org/licenses/by-nd/3.0/#
//
// Disclaimer:
// - using OpenIDFA requires understanding the difference between IDFA and OpenIDFA (see full comparison on http://OpenIDFA.org)
// - software is provided as is, comes with no guarantee
// - the author or APPSFIRE may not be held liable in any way for any issue arising from the use of OpenIDFA
//
#import <Foundation/Foundation.h>
View
@@ -0,0 +1,237 @@
//
// OpenIDFA.m
//
// NON PRODUCTION RELEASE VERSION 0.9
//
// Authored by Yann Lechelle on 07 Feb 2014.
// Open sourced to early adopters for private peer-review on 12 Feb 2014.
// Updated for stability on 19 Feb 2014.
// Open sourced to the wider community on 18 March 2014.
// Copyright (c) 2014 APPSFIRE.
//
// Homepage: http://OpenIDFA.org
// Twitter: @openIDFA
//
// This piece of code is released under the Creative Commons licence with "Attribution + No Derivatives" (CC BY-ND) http://creativecommons.org/licenses/by-nd/3.0/#
//
// Disclaimer:
// - using OpenIDFA requires understanding the difference between IDFA and OpenIDFA (see full comparison on http://OpenIDFA.org)
// - software is provided as is, comes with no guarantee
// - the author or APPSFIRE may not be held liable in any way for any issue arising from the use of OpenIDFA
//
#import "OpenIDFA.h"
#import <CommonCrypto/CommonDigest.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <sys/types.h>
@implementation OpenIDFA
+ (NSString*) sameDayOpenIDFA
{
return [[OpenIDFA threeDaysOpenIDFAArray] objectAtIndex:0];
}
+ (NSArray*) threeDaysOpenIDFAArray {
// The following list represents a rather large array of ids used to detect
// the presence of a number of apps available on the device. The apps on this
// list have been handpicked by Appsfire AppGenome engine; they each carry
// a statistically significant weight to define and differentiate a user from
// another. For the purpose of obfuscation inside the lib, we only used apps
// with Facebook-related URLHanders typically starting with the string "fb"
// then followed by a numerical string.
//
// RATIONALE: an "appmap" profile may vary over time, however, the likeness that it
// evolves between two tracking events over a large proportion of the user
// base is low.
//
// NOTICE: this list is the property of Appsfire and may not be extracted from
// the context of OpenIDFA which is governed by a Creative Commons (No Derivatives)
//
NSArray* base = @[ @101015295179ll, @102443183283204ll, @105130332854716ll, @110633906966ll, @111774748922919ll, @112953085413703ll, @113174082133029ll, @113246946530ll, @114870218560647ll, @115829135094686ll, @115862191798713ll, @118506164848956ll, @118589468194837ll, @118881298142408ll, @120176898077068ll, @121848807893603ll, @123448314320ll, @123591657714831ll, @124024574287414ll, @127449357267488ll, @127995567256931ll, @132363533491609ll, @134841016914ll, @138326442889677ll, @138713932872514ll, @146348772076164ll, @147364571964693ll, @147712241956950ll, @148327618516767ll, @152777738124418ll, @154615291248069ll, @156017694504926ll, @158761204309396ll, @159248674166087ll, @160888540611569ll, @161500167252219ll, @161599933913761ll, @162729813767876ll, @165482230209033ll, @176151905794941ll, @177821765590225ll, @178508429994ll, @192454074134796ll, @194714260574159ll, @208559595824260ll, @209864595695358ll, @210068525731476ll, @239823722730183ll, @246290217488ll, @255472420580ll, @267160383314960ll, @292065597989ll, @99197768694ll, @342234513642ll, @349724985922ll, @99554596360ll, @40343401983ll, @500407959994978ll, @52216716219ll, @90376669494ll];
// Playing with the prefix some more for the purpose of obfuscation
//
NSMutableString* _s_appmap = [NSMutableString stringWithString:@""];
NSString* _s = @"/";
NSString* _c = @":";
NSString* _b = @"b";
NSString* _f = @"f";
// Computing the "appmap" profile string for this user
// STRENGTH: potential of 2^61 distinct combinations
//
[_s_appmap appendString:[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@%@%@%@",_f,_b,_c,_s,_s]]]?@"|":@"-"];
for (id baseid in base) {
[_s_appmap appendString:[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@%@%@%@%@",_f,_b,[baseid stringValue],_c,_s,_s]]]?@"|":@"-"];
}
// Collecting the device boottime (Unix epoch) and turn it into a string
//
// RATIONALE: any reboot will cause former OpenIDFAs for this user to be
// invalidated and useless. This is a built-in property of OpenIDFA that
// wants to ensure that tokens expire regularly, and in this case, non-
// determiniscally.
//
// COMPLEXITY: boottime is NOT stable. Few days after releasing the lib,
// I realized that the clock was adjusted by 2 seconds per day on an actual
// device probably due to real-time clock adjustments over NTP.
//
// SOLUTION: truncating the right hand side of the boottime by 4 digits
// This allows the boottime to slide by up to 9999 seconds... many days!
// Side benefits, reboots within a 2.77h window will NOT reset the IDFA
//
// STRENGTH: iOS devices do not reboot often (ahem, version 7.1+!)
// Typical reboot occurs days if not weeks apart. Using one week,
// gives us 600k distinct possibilities assuming a random distribution
// of reboots across all devices
//
size_t size;
struct timeval boottime;
int mib[2] = {CTL_KERN, KERN_BOOTTIME};
size = sizeof(boottime);
NSString* _s_bt = @"";
if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) {
_s_bt =[NSString stringWithFormat:@"%lu",boottime.tv_sec];
_s_bt = [_s_bt substringToIndex:[_s_bt length]-4];
}
// Collecting the device "machine" identifier
//
// STRENGTH: 20+ combinations
//
// WEAKNESS: compared to Android, iOS pales here :) oh wait...
//
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *machine = malloc(size);
sysctlbyname("hw.machine", machine, &size, NULL, 0);
NSString *_s_machine = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];
free(machine);
// Collecting the device "model" identifier, for completition
//
// STRENGTH: adds little, helps in case of simulator
//
sysctlbyname("hw.model", NULL, &size, NULL, 0);
char *model = malloc(size);
sysctlbyname("hw.model", model, &size, NULL, 0);
NSString *_s_model = [NSString stringWithCString:model encoding:NSUTF8StringEncoding];
free(model);
// Collecting the locale country code
//
// STRENGTH: its complicated, but at least 80 combinations not evenly distributed!
// Check CLDR release 24 to know more: http://cldr.unicode.org/index/downloads/cldr-24
//
NSString *_s_ccode = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];
// Collecting an ordered array of preferred languages
//
// RATIONALE: this is an ordered list of preferred languages, theoretically speaking
// Most people only configure one and thefore the rest of the list remains unchanged
// However, polyglots will impact this list deeply.
// I've chosen to only mark up to 8 languages. Infiniglots don't pass the Turing test.
//
// STRENGTH: something like 8! but not evenly distributed.
//
NSArray* preferredLang = [NSLocale preferredLanguages];
NSString* _s_langs;
if (preferredLang == nil || ![preferredLang isKindOfClass:[NSArray class]] || [ preferredLang count ] == 0)
_s_langs = @"en";
else
_s_langs = [[preferredLang subarrayWithRange:NSMakeRange(0, MIN(8,[preferredLang count]))] componentsJoinedByString:@""];
// Collecting a few more device specific discriminating strings
//
// RATIONALE: the goal is to reinfoce uniqueness / reduce collisions.
// 1/ memory size: iOS devices come in variations of 8Gb, 16Gb, 32Gb, and 64Gb
// 2/ OS version: unevenly distributed, most people tend to have the latest version
// in iOS world... which is good! distinctiveness value = close to zero
// 3/ timezone: assuming equal distribution, 24 variations. Though we intuitively
// all know which 8 to 10 timezones represent 90% of all iOS devices!
//
// STRENGTH: say 50 combinations.
//
NSDictionary *fattributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil];
NSString *_s_disk = [[fattributes objectForKey:NSFileSystemSize] stringValue];
NSString* _s_osv = [[UIDevice currentDevice] systemVersion];
NSString* _s_tmz = [[NSTimeZone systemTimeZone] name];
// Marking the day, sameDay™, tomorrow or day after
//
// RATIONALE: this is another built-in and unique property of OpenIDFA
// The token is only valid for today (and the next two days).
// Tthe notion of day is pegged to the user himself, to their own
// biological clock. Assumption and experience is that most transactions
// occur within the same waking hours. So the notion of day was shifted
// by 4 hours (i.e. day begins at 4am, ends at 4am next day).
// The following study/graph by MixPanel illustrates this quite well:
// http://tctechcrunch2011.files.wordpress.com/2014/02/day-in-mobile-california.png?w=1280
// When tracking precision requires more than sameDay™, then tracker
// can venture into getting 3 days worth of OpenIDFA tokens...
//
NSDateFormatter* dateFormatter = [ [ NSDateFormatter alloc ] init ];
[ dateFormatter setDateFormat:@"yyMMdd" ];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *hourShift = [[NSDateComponents alloc] init];
[hourShift setHour:-4];
NSDate *currentDay= [calendar dateByAddingComponents:hourShift toDate:[NSDate date] options:0];
NSDateComponents *dayShift = [[NSDateComponents alloc] init];
[dayShift setDay:1];
// Creating array of 3 OpenIDFAs
//
NSMutableArray* openIDFAs = [NSMutableArray arrayWithCapacity:3];
for (int j=0; j<3; j++) {
// Creating the fingerprint with the various elements
// PART 1: Boot Time
// PART 2: Mostly stable and unique elements over time
// PART 3: Day Stamp
//
NSString* _s_day = [dateFormatter stringFromDate:currentDay];
NSString* fingerprint = [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@ %@ %@ %@ %@",
_s_bt, _s_disk,
_s_machine, _s_model,
_s_osv, _s_ccode,
_s_langs, _s_appmap,
_s_tmz, _s_day];
const char* str = [fingerprint UTF8String];
unsigned char result[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(str, (CC_LONG)strlen(str), result);
// Creating a UUID-like formatting by only taking one byte out of two from
// the SHA-256 Hash, and by inserting dashes where relevant.
// Should anyone see benefits in better compliance with http://www.itu.int/rec/T-REC-X.667/en
// especially perhaps the version number represented by bits 49 to 52, then raise your hand!
//
NSMutableString *hash = [NSMutableString stringWithCapacity:36];
for(int i = 0; i<CC_SHA256_DIGEST_LENGTH; i+=2)
{
if (i==8 || i==12 || i==16 || i==20)
[hash appendString:@"-"];
[hash appendFormat:@"%02X",result[i]];
}
[openIDFAs addObject:hash];
//NSLog(@"day[%d]%@",j,fingerprint);
//NSLog(@"HASH%d: %@",j,hash);
// Shifting day by one
//
currentDay = [calendar dateByAddingComponents:dayShift toDate:currentDay options:0];
}
//NSLog(@"OpenIDFAs: %@",openIDFAs);
return openIDFAs;
}
@end
View

This file was deleted.

Oops, something went wrong.
View
@@ -1,8 +1,7 @@
#OpenIDFA: the sustainable and privacy friendly tracking identifier for iOS
###"The Snapchat of Device IDs"
#####Now open for peer review [[register here][8]]
![](https://raw.github.com/ylechelle/OpenIDFA/82191382b0a399d50038522899ffd2ee1b3f6bf8/artwork/OpenIDFA_256x256.png)
![](http://f.cl.ly/items/2M251Z2i0E1h1E2z140w/Untitled_12.jpg)
##Synopsis
[Apple is wreaking havoc by rejecting apps using IDFA for non advertising purposes][4]. While this is a legitimate intent, enforcement by way of app rejection will penalize those who use it correctly, and yet, fall on the wrong side of interpretation. OpenIDFA offers a compelling alternative that does not depend on Apple’s own frameworks and guidelines, while at the same time helping with general privacy concerns.
@@ -66,13 +65,12 @@ Is it compliant with the law? Certainly. If anything, OpenIDFA is more ephemerea
- *Conversion tracking:* use OpenIDFA to record an impression, a click event (a tap really!), and then once the advertised app is installed and launched, match the current OpenIDFA to attribute the source...
- *Pre-impression event tracking for re-engagement and re-targeting:* use OpenIDFA to track e-commerce events inside the advertiser app; then match the OpenIDFA on the publisher’s side to present a higher impact advertisement...
####Why call it open when it's actually not open source?
####How open is OpenIDFA?
First there was OpenUDID, now OpenIDFA. Seemed fitting no?
OpenIDFA is provided as a static library that somewhat protects the inherent properties that limit tracking; as such, it is not open-source. Yet, OpenIDFA remains open and free to use by all, in a decentralized fashion, as was the case for OpenUDID. OpenIDFA is interoperable and not proprietary to any vendor. It’s part of the commons now. In fact, it is distributed under the Creative Commons license (Attribution BY + NoDerivatives ND).
OpenIDFA was initially provided as a static library to somewhat protects the inherent properties that limit long term persistent. Today, OpenIDFA is open source and free to be reviewed and used by all, in a decentralized fashion, as was the case for OpenUDID. OpenIDFA is interoperable and not proprietary to any vendor. It’s part of the commons now. In fact, it is distributed under the Creative Commons license (Attribution BY + NoDerivatives ND).
Now, about that source code: leap of faith, for now! Though the code is deceivingly simple. The essence lies in the acceptance that tracking tokens MUST expire, sooner rather than later (instead of explicit reset or limitations enacted by the user as is the case with the current IDFA system). Once that baseline is secured, the code follows the function and vice-versa.
About the srouce code: again, the essence lies in the acceptance that tracking tokens MUST expire, sooner rather than later (instead of explicit reset or limitations enacted by the user as is the case with the current IDFA system). Once that baseline is secured, the code follows the function and vice-versa.
As stated above, the code is locked up inside that lib. Feel free to reverse engineer it, you're likely to be deceived actually! That being said, the code is not meant to remain a mystery. [Register here][8] if you would like to be considered for preliminary peer-review.
####How much does it cost? When is it available?
@@ -91,7 +89,7 @@ Apple’s way:
The High Way:
// add the OpenIDFA.a static library
// add the OpenIDFA.h and OpenIDFA.m to your project
#import "OpenIDFA.h"
NSString* OpenIDFA = [OpenIDFA sameDayOpenIDFA];
@@ -119,9 +117,11 @@ You can now breathe easy. You can purge your databases daily (remember, those Op
##MISCELLANEOUS
#####Version History
- Feb 4 2014: birth of the OpenIDFA project
- Feb 7 2014: release on GitHub
- Feb 04 2014: birth of the OpenIDFA project
- Feb 07 2014: release of static library GitHub
- Feb 12 2014: source released to a selection of early adopters for peer review
- Mar 18 2014: source released to the greater community
####Follow OpenIDFA on Twitter
http://twitter.com/OpenIDFA
@@ -135,4 +135,3 @@ Why do we find out about important evolutions in the way the iOS APIs are to be
[5]: https://developer.apple.com "apple.com developer"
[6]: https://developer.apple.com/library/ios/documentation/AdSupport/Reference/ASIdentifierManager_Ref/ASIdentifierManager.html "IDFA"
[7]: http://OpenIDFA.org "OpenIDFA"
[8]: https://docs.google.com/forms/d/1ynocrB2Zeern0_bzpZoREE_2OXMd8Pgh-nO9kda6N6g/viewform "Register for Code"
View
Binary file not shown.

0 comments on commit f8c726c

Please sign in to comment.